13 changed files with 541 additions and 20 deletions
@ -0,0 +1,211 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package queue |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"fmt" |
||||
"reflect" |
||||
"sort" |
||||
"sync" |
||||
"time" |
||||
) |
||||
|
||||
var manager *Manager |
||||
|
||||
// Manager is a queue manager
|
||||
type Manager struct { |
||||
mutex sync.Mutex |
||||
|
||||
counter int64 |
||||
Queues map[int64]*Description |
||||
} |
||||
|
||||
// Description represents a working queue inheriting from Gitea.
|
||||
type Description struct { |
||||
mutex sync.Mutex |
||||
QID int64 |
||||
Queue Queue |
||||
Type Type |
||||
Name string |
||||
Configuration interface{} |
||||
ExemplarType string |
||||
addWorkers func(number int, timeout time.Duration) context.CancelFunc |
||||
numberOfWorkers func() int |
||||
counter int64 |
||||
PoolWorkers map[int64]*PoolWorkers |
||||
} |
||||
|
||||
// DescriptionList implements the sort.Interface
|
||||
type DescriptionList []*Description |
||||
|
||||
// PoolWorkers represents a working queue inheriting from Gitea.
|
||||
type PoolWorkers struct { |
||||
PID int64 |
||||
Workers int |
||||
Start time.Time |
||||
Timeout time.Time |
||||
HasTimeout bool |
||||
Cancel context.CancelFunc |
||||
} |
||||
|
||||
// PoolWorkersList implements the sort.Interface
|
||||
type PoolWorkersList []*PoolWorkers |
||||
|
||||
func init() { |
||||
_ = GetManager() |
||||
} |
||||
|
||||
// GetManager returns a Manager and initializes one as singleton if there's none yet
|
||||
func GetManager() *Manager { |
||||
if manager == nil { |
||||
manager = &Manager{ |
||||
Queues: make(map[int64]*Description), |
||||
} |
||||
} |
||||
return manager |
||||
} |
||||
|
||||
// Add adds a queue to this manager
|
||||
func (m *Manager) Add(queue Queue, |
||||
t Type, |
||||
configuration, |
||||
exemplar interface{}, |
||||
addWorkers func(number int, timeout time.Duration) context.CancelFunc, |
||||
numberOfWorkers func() int) int64 { |
||||
|
||||
cfg, _ := json.Marshal(configuration) |
||||
desc := &Description{ |
||||
Queue: queue, |
||||
Type: t, |
||||
Configuration: string(cfg), |
||||
ExemplarType: reflect.TypeOf(exemplar).String(), |
||||
PoolWorkers: make(map[int64]*PoolWorkers), |
||||
addWorkers: addWorkers, |
||||
numberOfWorkers: numberOfWorkers, |
||||
} |
||||
m.mutex.Lock() |
||||
m.counter++ |
||||
desc.QID = m.counter |
||||
desc.Name = fmt.Sprintf("queue-%d", desc.QID) |
||||
if named, ok := queue.(Named); ok { |
||||
desc.Name = named.Name() |
||||
} |
||||
m.Queues[desc.QID] = desc |
||||
m.mutex.Unlock() |
||||
return desc.QID |
||||
} |
||||
|
||||
// Remove a queue from the Manager
|
||||
func (m *Manager) Remove(qid int64) { |
||||
m.mutex.Lock() |
||||
delete(m.Queues, qid) |
||||
m.mutex.Unlock() |
||||
} |
||||
|
||||
// GetDescription by qid
|
||||
func (m *Manager) GetDescription(qid int64) *Description { |
||||
m.mutex.Lock() |
||||
defer m.mutex.Unlock() |
||||
return m.Queues[qid] |
||||
} |
||||
|
||||
// Descriptions returns the queue descriptions
|
||||
func (m *Manager) Descriptions() []*Description { |
||||
m.mutex.Lock() |
||||
descs := make([]*Description, 0, len(m.Queues)) |
||||
for _, desc := range m.Queues { |
||||
descs = append(descs, desc) |
||||
} |
||||
m.mutex.Unlock() |
||||
sort.Sort(DescriptionList(descs)) |
||||
return descs |
||||
} |
||||
|
||||
// Workers returns the poolworkers
|
||||
func (q *Description) Workers() []*PoolWorkers { |
||||
q.mutex.Lock() |
||||
workers := make([]*PoolWorkers, 0, len(q.PoolWorkers)) |
||||
for _, worker := range q.PoolWorkers { |
||||
workers = append(workers, worker) |
||||
} |
||||
q.mutex.Unlock() |
||||
sort.Sort(PoolWorkersList(workers)) |
||||
return workers |
||||
} |
||||
|
||||
// RegisterWorkers registers workers to this queue
|
||||
func (q *Description) RegisterWorkers(number int, start time.Time, hasTimeout bool, timeout time.Time, cancel context.CancelFunc) int64 { |
||||
q.mutex.Lock() |
||||
defer q.mutex.Unlock() |
||||
q.counter++ |
||||
q.PoolWorkers[q.counter] = &PoolWorkers{ |
||||
PID: q.counter, |
||||
Workers: number, |
||||
Start: start, |
||||
Timeout: timeout, |
||||
HasTimeout: hasTimeout, |
||||
Cancel: cancel, |
||||
} |
||||
return q.counter |
||||
} |
||||
|
||||
// CancelWorkers cancels pooled workers with pid
|
||||
func (q *Description) CancelWorkers(pid int64) { |
||||
q.mutex.Lock() |
||||
pw, ok := q.PoolWorkers[pid] |
||||
q.mutex.Unlock() |
||||
if !ok { |
||||
return |
||||
} |
||||
pw.Cancel() |
||||
} |
||||
|
||||
// RemoveWorkers deletes pooled workers with pid
|
||||
func (q *Description) RemoveWorkers(pid int64) { |
||||
q.mutex.Lock() |
||||
delete(q.PoolWorkers, pid) |
||||
q.mutex.Unlock() |
||||
} |
||||
|
||||
// AddWorkers adds workers to the queue if it has registered an add worker function
|
||||
func (q *Description) AddWorkers(number int, timeout time.Duration) { |
||||
if q.addWorkers != nil { |
||||
_ = q.addWorkers(number, timeout) |
||||
} |
||||
} |
||||
|
||||
// NumberOfWorkers returns the number of workers in the queue
|
||||
func (q *Description) NumberOfWorkers() int { |
||||
if q.numberOfWorkers != nil { |
||||
return q.numberOfWorkers() |
||||
} |
||||
return -1 |
||||
} |
||||
|
||||
func (l DescriptionList) Len() int { |
||||
return len(l) |
||||
} |
||||
|
||||
func (l DescriptionList) Less(i, j int) bool { |
||||
return l[i].Name < l[j].Name |
||||
} |
||||
|
||||
func (l DescriptionList) Swap(i, j int) { |
||||
l[i], l[j] = l[j], l[i] |
||||
} |
||||
|
||||
func (l PoolWorkersList) Len() int { |
||||
return len(l) |
||||
} |
||||
|
||||
func (l PoolWorkersList) Less(i, j int) bool { |
||||
return l[i].Start.Before(l[j].Start) |
||||
} |
||||
|
||||
func (l PoolWorkersList) Swap(i, j int) { |
||||
l[i], l[j] = l[j], l[i] |
||||
} |
@ -0,0 +1,117 @@
|
||||
{{template "base/head" .}} |
||||
<div class="admin monitor"> |
||||
{{template "admin/navbar" .}} |
||||
<div class="ui container"> |
||||
{{template "base/alert" .}} |
||||
<h4 class="ui top attached header"> |
||||
{{.i18n.Tr "admin.monitor.queue" .Queue.Name}} |
||||
</h4> |
||||
<div class="ui attached table segment"> |
||||
<table class="ui very basic striped table"> |
||||
<thead> |
||||
<tr> |
||||
<th>{{.i18n.Tr "admin.monitor.queue.name"}}</th> |
||||
<th>{{.i18n.Tr "admin.monitor.queue.type"}}</th> |
||||
<th>{{.i18n.Tr "admin.monitor.queue.exemplar"}}</th> |
||||
<th>{{.i18n.Tr "admin.monitor.queue.numberworkers"}}</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<tr> |
||||
<td>{{.Queue.Name}}</td> |
||||
<td>{{.Queue.Type}}</td> |
||||
<td>{{.Queue.ExemplarType}}</td> |
||||
<td>{{$sum := .Queue.NumberOfWorkers}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td> |
||||
</tr> |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
{{if lt $sum 0 }} |
||||
<h4 class="ui top attached header"> |
||||
{{.i18n.Tr "admin.monitor.queue.nopool.title"}} |
||||
</h4> |
||||
<div class="ui attached segment"> |
||||
{{if eq .Queue.Type "wrapped" }} |
||||
<p>{{.i18n.Tr "admin.monitor.queue.wrapped.desc"}}</p> |
||||
{{else if eq .Queue.Type "persistable-channel"}} |
||||
<p>{{.i18n.Tr "admin.monitor.queue.persistable-channel.desc"}}</p> |
||||
{{else}} |
||||
<p>{{.i18n.Tr "admin.monitor.queue.nopool.desc"}}</p> |
||||
{{end}} |
||||
</div> |
||||
{{else}} |
||||
<h4 class="ui top attached header"> |
||||
{{.i18n.Tr "admin.monitor.queue.pool.addworkers.title"}} |
||||
</h4> |
||||
<div class="ui attached segment"> |
||||
<p>{{.i18n.Tr "admin.monitor.queue.pool.addworkers.desc"}}</p> |
||||
<form method="POST" action="{{.Link}}/add"> |
||||
{{$.CsrfTokenHtml}} |
||||
<div class="ui form"> |
||||
<div class="fields"> |
||||
<div class="field"> |
||||
<label>{{.i18n.Tr "admin.monitor.queue.numberworkers"}}</label> |
||||
<input name="number" type="text" placeholder="{{.i18n.Tr "admin.monitor.queue.pool.addworkers.numberworkers.placeholder"}}"> |
||||
</div> |
||||
<div class="field"> |
||||
<label>{{.i18n.Tr "admin.monitor.queue.pool.timeout"}}</label> |
||||
<input name="timeout" type="text" placeholder="{{.i18n.Tr "admin.monitor.queue.pool.addworkers.timeout.placeholder"}}"> |
||||
</div> |
||||
</div> |
||||
<button class="ui submit button">{{.i18n.Tr "admin.monitor.queue.pool.addworkers.submit"}}</button> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
<h4 class="ui top attached header"> |
||||
{{.i18n.Tr "admin.monitor.queue.pool.workers.title"}} |
||||
</h4> |
||||
<div class="ui attached table segment"> |
||||
<table class="ui very basic striped table"> |
||||
<thead> |
||||
<tr> |
||||
<th>{{.i18n.Tr "admin.monitor.queue.numberworkers"}}</th> |
||||
<th>{{.i18n.Tr "admin.monitor.start"}}</th> |
||||
<th>{{.i18n.Tr "admin.monitor.queue.pool.timeout"}}</th> |
||||
<th></th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
{{range .Queue.Workers}} |
||||
<tr> |
||||
<td>{{.Workers}}</td> |
||||
<td>{{DateFmtLong .Start}}</td> |
||||
<td>{{if .HasTimeout}}{{DateFmtLong .Timeout}}{{else}}-{{end}}</td> |
||||
<td> |
||||
<a class="delete-button" href="" data-url="{{$.Link}}/cancel/{{.PID}}" data-id="{{.PID}}" data-name="{{.Workers}}"><i class="close icon text red" title="{{$.i18n.Tr "remove"}}"></i></a> |
||||
</td> |
||||
</tr> |
||||
{{else}} |
||||
<tr> |
||||
<td colspan="4">{{.i18n.Tr "admin.monitor.queue.pool.workers.none" }} |
||||
</tr> |
||||
{{end}} |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
{{end}} |
||||
<h4 class="ui top attached header"> |
||||
{{.i18n.Tr "admin.monitor.queue.configuration"}} |
||||
</h4> |
||||
<div class="ui attached segment"> |
||||
<pre>{{.Queue.Configuration | JsonPrettyPrint}} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="ui small basic delete modal"> |
||||
<div class="ui icon header"> |
||||
<i class="close icon"></i> |
||||
{{.i18n.Tr "admin.monitor.queue.pool.cancel"}} |
||||
</div> |
||||
<div class="content"> |
||||
<p>{{$.i18n.Tr "admin.monitor.queue.pool.cancel_notices" `<span class="name"></span>` | Safe}}</p> |
||||
<p>{{$.i18n.Tr "admin.monitor.queue.pool.cancel_desc"}}</p> |
||||
</div> |
||||
{{template "base/delete_modal_actions" .}} |
||||
</div> |
||||
|
||||
{{template "base/footer" .}} |
Loading…
Reference in new issue