mirror of
https://github.com/go-gitea/gitea.git
synced 2025-01-03 14:57:55 -05:00
Add MaxWorker settings to queues
This commit is contained in:
parent
a492b3071c
commit
b1c9fa7f1a
@ -28,17 +28,28 @@ type Manager struct {
|
|||||||
|
|
||||||
// Description represents a working queue inheriting from Gitea.
|
// Description represents a working queue inheriting from Gitea.
|
||||||
type Description struct {
|
type Description struct {
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
QID int64
|
QID int64
|
||||||
Queue Queue
|
Queue Queue
|
||||||
Type Type
|
Type Type
|
||||||
Name string
|
Name string
|
||||||
Configuration interface{}
|
Configuration interface{}
|
||||||
ExemplarType string
|
ExemplarType string
|
||||||
addWorkers func(number int, timeout time.Duration) context.CancelFunc
|
Pool PoolManager
|
||||||
numberOfWorkers func() int
|
counter int64
|
||||||
counter int64
|
PoolWorkers map[int64]*PoolWorkers
|
||||||
PoolWorkers map[int64]*PoolWorkers
|
}
|
||||||
|
|
||||||
|
// PoolManager is a simple interface to get certain details from a worker pool
|
||||||
|
type PoolManager interface {
|
||||||
|
AddWorkers(number int, timeout time.Duration) context.CancelFunc
|
||||||
|
NumberOfWorkers() int
|
||||||
|
MaxNumberOfWorkers() int
|
||||||
|
SetMaxNumberOfWorkers(int)
|
||||||
|
BoostTimeout() time.Duration
|
||||||
|
BlockTimeout() time.Duration
|
||||||
|
BoostWorkers() int
|
||||||
|
SetSettings(maxNumberOfWorkers, boostWorkers int, timeout time.Duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DescriptionList implements the sort.Interface
|
// DescriptionList implements the sort.Interface
|
||||||
@ -76,18 +87,16 @@ func (m *Manager) Add(queue Queue,
|
|||||||
t Type,
|
t Type,
|
||||||
configuration,
|
configuration,
|
||||||
exemplar interface{},
|
exemplar interface{},
|
||||||
addWorkers func(number int, timeout time.Duration) context.CancelFunc,
|
pool PoolManager) int64 {
|
||||||
numberOfWorkers func() int) int64 {
|
|
||||||
|
|
||||||
cfg, _ := json.Marshal(configuration)
|
cfg, _ := json.Marshal(configuration)
|
||||||
desc := &Description{
|
desc := &Description{
|
||||||
Queue: queue,
|
Queue: queue,
|
||||||
Type: t,
|
Type: t,
|
||||||
Configuration: string(cfg),
|
Configuration: string(cfg),
|
||||||
ExemplarType: reflect.TypeOf(exemplar).String(),
|
ExemplarType: reflect.TypeOf(exemplar).String(),
|
||||||
PoolWorkers: make(map[int64]*PoolWorkers),
|
PoolWorkers: make(map[int64]*PoolWorkers),
|
||||||
addWorkers: addWorkers,
|
Pool: pool,
|
||||||
numberOfWorkers: numberOfWorkers,
|
|
||||||
}
|
}
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
m.counter++
|
m.counter++
|
||||||
@ -177,20 +186,61 @@ func (q *Description) RemoveWorkers(pid int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddWorkers adds workers to the queue if it has registered an add worker function
|
// AddWorkers adds workers to the queue if it has registered an add worker function
|
||||||
func (q *Description) AddWorkers(number int, timeout time.Duration) {
|
func (q *Description) AddWorkers(number int, timeout time.Duration) context.CancelFunc {
|
||||||
if q.addWorkers != nil {
|
if q.Pool != nil {
|
||||||
_ = q.addWorkers(number, timeout)
|
// the cancel will be added to the pool workers description above
|
||||||
|
return q.Pool.AddWorkers(number, timeout)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumberOfWorkers returns the number of workers in the queue
|
// NumberOfWorkers returns the number of workers in the queue
|
||||||
func (q *Description) NumberOfWorkers() int {
|
func (q *Description) NumberOfWorkers() int {
|
||||||
if q.numberOfWorkers != nil {
|
if q.Pool != nil {
|
||||||
return q.numberOfWorkers()
|
return q.Pool.NumberOfWorkers()
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaxNumberOfWorkers returns the maximum number of workers for the pool
|
||||||
|
func (q *Description) MaxNumberOfWorkers() int {
|
||||||
|
if q.Pool != nil {
|
||||||
|
return q.Pool.MaxNumberOfWorkers()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoostWorkers returns the number of workers for a boost
|
||||||
|
func (q *Description) BoostWorkers() int {
|
||||||
|
if q.Pool != nil {
|
||||||
|
return q.Pool.BoostWorkers()
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoostTimeout returns the timeout of the next boost
|
||||||
|
func (q *Description) BoostTimeout() time.Duration {
|
||||||
|
if q.Pool != nil {
|
||||||
|
return q.Pool.BoostTimeout()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockTimeout returns the timeout til the next boost
|
||||||
|
func (q *Description) BlockTimeout() time.Duration {
|
||||||
|
if q.Pool != nil {
|
||||||
|
return q.Pool.BlockTimeout()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSettings sets the setable boost values
|
||||||
|
func (q *Description) SetSettings(maxNumberOfWorkers, boostWorkers int, timeout time.Duration) {
|
||||||
|
if q.Pool != nil {
|
||||||
|
q.Pool.SetSettings(maxNumberOfWorkers, boostWorkers, timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l DescriptionList) Len() int {
|
func (l DescriptionList) Len() int {
|
||||||
return len(l)
|
return len(l)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ type ChannelQueueConfiguration struct {
|
|||||||
QueueLength int
|
QueueLength int
|
||||||
BatchLength int
|
BatchLength int
|
||||||
Workers int
|
Workers int
|
||||||
|
MaxWorkers int
|
||||||
BlockTimeout time.Duration
|
BlockTimeout time.Duration
|
||||||
BoostTimeout time.Duration
|
BoostTimeout time.Duration
|
||||||
BoostWorkers int
|
BoostWorkers int
|
||||||
@ -50,20 +51,21 @@ func NewChannelQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, erro
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
queue := &ChannelQueue{
|
queue := &ChannelQueue{
|
||||||
pool: &WorkerPool{
|
pool: &WorkerPool{
|
||||||
baseCtx: ctx,
|
baseCtx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
batchLength: config.BatchLength,
|
batchLength: config.BatchLength,
|
||||||
handle: handle,
|
handle: handle,
|
||||||
dataChan: dataChan,
|
dataChan: dataChan,
|
||||||
blockTimeout: config.BlockTimeout,
|
blockTimeout: config.BlockTimeout,
|
||||||
boostTimeout: config.BoostTimeout,
|
boostTimeout: config.BoostTimeout,
|
||||||
boostWorkers: config.BoostWorkers,
|
boostWorkers: config.BoostWorkers,
|
||||||
|
maxNumberOfWorkers: config.MaxWorkers,
|
||||||
},
|
},
|
||||||
exemplar: exemplar,
|
exemplar: exemplar,
|
||||||
workers: config.Workers,
|
workers: config.Workers,
|
||||||
name: config.Name,
|
name: config.Name,
|
||||||
}
|
}
|
||||||
queue.pool.qid = GetManager().Add(queue, ChannelQueueType, config, exemplar, queue.pool.AddWorkers, queue.pool.NumberOfWorkers)
|
queue.pool.qid = GetManager().Add(queue, ChannelQueueType, config, exemplar, queue.pool)
|
||||||
return queue, nil
|
return queue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ func TestChannelQueue(t *testing.T) {
|
|||||||
ChannelQueueConfiguration{
|
ChannelQueueConfiguration{
|
||||||
QueueLength: 20,
|
QueueLength: 20,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 10,
|
||||||
BlockTimeout: 1 * time.Second,
|
BlockTimeout: 1 * time.Second,
|
||||||
BoostTimeout: 5 * time.Minute,
|
BoostTimeout: 5 * time.Minute,
|
||||||
BoostWorkers: 5,
|
BoostWorkers: 5,
|
||||||
@ -62,6 +63,7 @@ func TestChannelQueue_Batch(t *testing.T) {
|
|||||||
QueueLength: 20,
|
QueueLength: 20,
|
||||||
BatchLength: 2,
|
BatchLength: 2,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 10,
|
||||||
BlockTimeout: 1 * time.Second,
|
BlockTimeout: 1 * time.Second,
|
||||||
BoostTimeout: 5 * time.Minute,
|
BoostTimeout: 5 * time.Minute,
|
||||||
BoostWorkers: 5,
|
BoostWorkers: 5,
|
||||||
|
@ -25,6 +25,7 @@ type LevelQueueConfiguration struct {
|
|||||||
QueueLength int
|
QueueLength int
|
||||||
BatchLength int
|
BatchLength int
|
||||||
Workers int
|
Workers int
|
||||||
|
MaxWorkers int
|
||||||
BlockTimeout time.Duration
|
BlockTimeout time.Duration
|
||||||
BoostTimeout time.Duration
|
BoostTimeout time.Duration
|
||||||
BoostWorkers int
|
BoostWorkers int
|
||||||
@ -60,14 +61,15 @@ func NewLevelQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error)
|
|||||||
|
|
||||||
queue := &LevelQueue{
|
queue := &LevelQueue{
|
||||||
pool: &WorkerPool{
|
pool: &WorkerPool{
|
||||||
baseCtx: ctx,
|
baseCtx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
batchLength: config.BatchLength,
|
batchLength: config.BatchLength,
|
||||||
handle: handle,
|
handle: handle,
|
||||||
dataChan: dataChan,
|
dataChan: dataChan,
|
||||||
blockTimeout: config.BlockTimeout,
|
blockTimeout: config.BlockTimeout,
|
||||||
boostTimeout: config.BoostTimeout,
|
boostTimeout: config.BoostTimeout,
|
||||||
boostWorkers: config.BoostWorkers,
|
boostWorkers: config.BoostWorkers,
|
||||||
|
maxNumberOfWorkers: config.MaxWorkers,
|
||||||
},
|
},
|
||||||
queue: internal,
|
queue: internal,
|
||||||
exemplar: exemplar,
|
exemplar: exemplar,
|
||||||
@ -76,7 +78,7 @@ func NewLevelQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error)
|
|||||||
workers: config.Workers,
|
workers: config.Workers,
|
||||||
name: config.Name,
|
name: config.Name,
|
||||||
}
|
}
|
||||||
queue.pool.qid = GetManager().Add(queue, LevelQueueType, config, exemplar, queue.pool.AddWorkers, queue.pool.NumberOfWorkers)
|
queue.pool.qid = GetManager().Add(queue, LevelQueueType, config, exemplar, queue.pool)
|
||||||
return queue, nil
|
return queue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ type PersistableChannelQueueConfiguration struct {
|
|||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
MaxAttempts int
|
MaxAttempts int
|
||||||
Workers int
|
Workers int
|
||||||
|
MaxWorkers int
|
||||||
BlockTimeout time.Duration
|
BlockTimeout time.Duration
|
||||||
BoostTimeout time.Duration
|
BoostTimeout time.Duration
|
||||||
BoostWorkers int
|
BoostWorkers int
|
||||||
@ -48,6 +49,7 @@ func NewPersistableChannelQueue(handle HandlerFunc, cfg, exemplar interface{}) (
|
|||||||
QueueLength: config.QueueLength,
|
QueueLength: config.QueueLength,
|
||||||
BatchLength: config.BatchLength,
|
BatchLength: config.BatchLength,
|
||||||
Workers: config.Workers,
|
Workers: config.Workers,
|
||||||
|
MaxWorkers: config.MaxWorkers,
|
||||||
BlockTimeout: config.BlockTimeout,
|
BlockTimeout: config.BlockTimeout,
|
||||||
BoostTimeout: config.BoostTimeout,
|
BoostTimeout: config.BoostTimeout,
|
||||||
BoostWorkers: config.BoostWorkers,
|
BoostWorkers: config.BoostWorkers,
|
||||||
@ -63,6 +65,7 @@ func NewPersistableChannelQueue(handle HandlerFunc, cfg, exemplar interface{}) (
|
|||||||
QueueLength: config.QueueLength,
|
QueueLength: config.QueueLength,
|
||||||
BatchLength: config.BatchLength,
|
BatchLength: config.BatchLength,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 6,
|
||||||
BlockTimeout: 1 * time.Second,
|
BlockTimeout: 1 * time.Second,
|
||||||
BoostTimeout: 5 * time.Minute,
|
BoostTimeout: 5 * time.Minute,
|
||||||
BoostWorkers: 5,
|
BoostWorkers: 5,
|
||||||
@ -96,7 +99,7 @@ func NewPersistableChannelQueue(handle HandlerFunc, cfg, exemplar interface{}) (
|
|||||||
},
|
},
|
||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
}
|
}
|
||||||
_ = GetManager().Add(queue, PersistableChannelQueueType, config, exemplar, nil, nil)
|
_ = GetManager().Add(queue, PersistableChannelQueueType, config, exemplar, nil)
|
||||||
return queue, nil
|
return queue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ func TestPersistableChannelQueue(t *testing.T) {
|
|||||||
BatchLength: 2,
|
BatchLength: 2,
|
||||||
QueueLength: 20,
|
QueueLength: 20,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 10,
|
||||||
}, &testData{})
|
}, &testData{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ func TestPersistableChannelQueue(t *testing.T) {
|
|||||||
BatchLength: 2,
|
BatchLength: 2,
|
||||||
QueueLength: 20,
|
QueueLength: 20,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 10,
|
||||||
}, &testData{})
|
}, &testData{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ func TestLevelQueue(t *testing.T) {
|
|||||||
DataDir: tmpDir,
|
DataDir: tmpDir,
|
||||||
BatchLength: 2,
|
BatchLength: 2,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 10,
|
||||||
QueueLength: 20,
|
QueueLength: 20,
|
||||||
BlockTimeout: 1 * time.Second,
|
BlockTimeout: 1 * time.Second,
|
||||||
BoostTimeout: 5 * time.Minute,
|
BoostTimeout: 5 * time.Minute,
|
||||||
@ -94,6 +95,7 @@ func TestLevelQueue(t *testing.T) {
|
|||||||
DataDir: tmpDir,
|
DataDir: tmpDir,
|
||||||
BatchLength: 2,
|
BatchLength: 2,
|
||||||
Workers: 1,
|
Workers: 1,
|
||||||
|
MaxWorkers: 10,
|
||||||
QueueLength: 20,
|
QueueLength: 20,
|
||||||
BlockTimeout: 1 * time.Second,
|
BlockTimeout: 1 * time.Second,
|
||||||
BoostTimeout: 5 * time.Minute,
|
BoostTimeout: 5 * time.Minute,
|
||||||
|
@ -49,6 +49,7 @@ type RedisQueueConfiguration struct {
|
|||||||
QueueLength int
|
QueueLength int
|
||||||
QueueName string
|
QueueName string
|
||||||
Workers int
|
Workers int
|
||||||
|
MaxWorkers int
|
||||||
BlockTimeout time.Duration
|
BlockTimeout time.Duration
|
||||||
BoostTimeout time.Duration
|
BoostTimeout time.Duration
|
||||||
BoostWorkers int
|
BoostWorkers int
|
||||||
@ -70,14 +71,15 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error)
|
|||||||
|
|
||||||
var queue = &RedisQueue{
|
var queue = &RedisQueue{
|
||||||
pool: &WorkerPool{
|
pool: &WorkerPool{
|
||||||
baseCtx: ctx,
|
baseCtx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
batchLength: config.BatchLength,
|
batchLength: config.BatchLength,
|
||||||
handle: handle,
|
handle: handle,
|
||||||
dataChan: dataChan,
|
dataChan: dataChan,
|
||||||
blockTimeout: config.BlockTimeout,
|
blockTimeout: config.BlockTimeout,
|
||||||
boostTimeout: config.BoostTimeout,
|
boostTimeout: config.BoostTimeout,
|
||||||
boostWorkers: config.BoostWorkers,
|
boostWorkers: config.BoostWorkers,
|
||||||
|
maxNumberOfWorkers: config.MaxWorkers,
|
||||||
},
|
},
|
||||||
queueName: config.QueueName,
|
queueName: config.QueueName,
|
||||||
exemplar: exemplar,
|
exemplar: exemplar,
|
||||||
@ -102,7 +104,7 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error)
|
|||||||
if err := queue.client.Ping().Err(); err != nil {
|
if err := queue.client.Ping().Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
queue.pool.qid = GetManager().Add(queue, RedisQueueType, config, exemplar, queue.pool.AddWorkers, queue.pool.NumberOfWorkers)
|
queue.pool.qid = GetManager().Add(queue, RedisQueueType, config, exemplar, queue.pool)
|
||||||
|
|
||||||
return queue, nil
|
return queue, nil
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ func NewWrappedQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, erro
|
|||||||
name: config.Name,
|
name: config.Name,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_ = GetManager().Add(queue, WrappedQueueType, config, exemplar, nil, nil)
|
_ = GetManager().Add(queue, WrappedQueueType, config, exemplar, nil)
|
||||||
return queue, nil
|
return queue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,24 +14,25 @@ import (
|
|||||||
|
|
||||||
// WorkerPool takes
|
// WorkerPool takes
|
||||||
type WorkerPool struct {
|
type WorkerPool struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
baseCtx context.Context
|
baseCtx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
cond *sync.Cond
|
cond *sync.Cond
|
||||||
qid int64
|
qid int64
|
||||||
numberOfWorkers int
|
maxNumberOfWorkers int
|
||||||
batchLength int
|
numberOfWorkers int
|
||||||
handle HandlerFunc
|
batchLength int
|
||||||
dataChan chan Data
|
handle HandlerFunc
|
||||||
blockTimeout time.Duration
|
dataChan chan Data
|
||||||
boostTimeout time.Duration
|
blockTimeout time.Duration
|
||||||
boostWorkers int
|
boostTimeout time.Duration
|
||||||
|
boostWorkers int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push pushes the data to the internal channel
|
// Push pushes the data to the internal channel
|
||||||
func (p *WorkerPool) Push(data Data) {
|
func (p *WorkerPool) Push(data Data) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
if p.blockTimeout > 0 && p.boostTimeout > 0 {
|
if p.blockTimeout > 0 && p.boostTimeout > 0 && (p.numberOfWorkers <= p.maxNumberOfWorkers || p.maxNumberOfWorkers < 0) {
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
p.pushBoost(data)
|
p.pushBoost(data)
|
||||||
} else {
|
} else {
|
||||||
@ -63,7 +64,7 @@ func (p *WorkerPool) pushBoost(data Data) {
|
|||||||
}
|
}
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
if p.blockTimeout > ourTimeout {
|
if p.blockTimeout > ourTimeout || (p.numberOfWorkers > p.maxNumberOfWorkers && p.maxNumberOfWorkers >= 0) {
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
p.dataChan <- data
|
p.dataChan <- data
|
||||||
return
|
return
|
||||||
@ -71,11 +72,15 @@ func (p *WorkerPool) pushBoost(data Data) {
|
|||||||
p.blockTimeout *= 2
|
p.blockTimeout *= 2
|
||||||
ctx, cancel := context.WithCancel(p.baseCtx)
|
ctx, cancel := context.WithCancel(p.baseCtx)
|
||||||
desc := GetManager().GetDescription(p.qid)
|
desc := GetManager().GetDescription(p.qid)
|
||||||
|
boost := p.boostWorkers
|
||||||
|
if (boost+p.numberOfWorkers) > p.maxNumberOfWorkers && p.maxNumberOfWorkers >= 0 {
|
||||||
|
boost = p.maxNumberOfWorkers - p.numberOfWorkers
|
||||||
|
}
|
||||||
if desc != nil {
|
if desc != nil {
|
||||||
log.Warn("WorkerPool: %d (for %s) Channel blocked for %v - adding %d temporary workers for %s, block timeout now %v", p.qid, desc.Name, ourTimeout, p.boostWorkers, p.boostTimeout, p.blockTimeout)
|
log.Warn("WorkerPool: %d (for %s) Channel blocked for %v - adding %d temporary workers for %s, block timeout now %v", p.qid, desc.Name, ourTimeout, boost, p.boostTimeout, p.blockTimeout)
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
pid := desc.RegisterWorkers(p.boostWorkers, start, false, start, cancel)
|
pid := desc.RegisterWorkers(boost, start, false, start, cancel)
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
desc.RemoveWorkers(pid)
|
desc.RemoveWorkers(pid)
|
||||||
@ -91,7 +96,7 @@ func (p *WorkerPool) pushBoost(data Data) {
|
|||||||
p.blockTimeout /= 2
|
p.blockTimeout /= 2
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
}()
|
}()
|
||||||
p.addWorkers(ctx, p.boostWorkers)
|
p.addWorkers(ctx, boost)
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
p.dataChan <- data
|
p.dataChan <- data
|
||||||
}
|
}
|
||||||
@ -105,7 +110,53 @@ func (p *WorkerPool) NumberOfWorkers() int {
|
|||||||
return p.numberOfWorkers
|
return p.numberOfWorkers
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddWorkers adds workers to the pool
|
// MaxNumberOfWorkers returns the maximum number of workers automatically added to the pool
|
||||||
|
func (p *WorkerPool) MaxNumberOfWorkers() int {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
return p.maxNumberOfWorkers
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoostWorkers returns the number of workers for a boost
|
||||||
|
func (p *WorkerPool) BoostWorkers() int {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
return p.boostWorkers
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoostTimeout returns the timeout of the next boost
|
||||||
|
func (p *WorkerPool) BoostTimeout() time.Duration {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
return p.boostTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockTimeout returns the timeout til the next boost
|
||||||
|
func (p *WorkerPool) BlockTimeout() time.Duration {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
return p.blockTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSettings sets the setable boost values
|
||||||
|
func (p *WorkerPool) SetSettings(maxNumberOfWorkers, boostWorkers int, timeout time.Duration) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
p.maxNumberOfWorkers = maxNumberOfWorkers
|
||||||
|
p.boostWorkers = boostWorkers
|
||||||
|
p.boostTimeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxNumberOfWorkers sets the maximum number of workers automatically added to the pool
|
||||||
|
// Changing this number will not change the number of current workers but will change the limit
|
||||||
|
// for future additions
|
||||||
|
func (p *WorkerPool) SetMaxNumberOfWorkers(newMax int) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
p.maxNumberOfWorkers = newMax
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWorkers adds workers to the pool - this allows the number of workers to go above the limit
|
||||||
func (p *WorkerPool) AddWorkers(number int, timeout time.Duration) context.CancelFunc {
|
func (p *WorkerPool) AddWorkers(number int, timeout time.Duration) context.CancelFunc {
|
||||||
var ctx context.Context
|
var ctx context.Context
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
|
@ -31,6 +31,7 @@ type queueSettings struct {
|
|||||||
MaxAttempts int
|
MaxAttempts int
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
Workers int
|
Workers int
|
||||||
|
MaxWorkers int
|
||||||
BlockTimeout time.Duration
|
BlockTimeout time.Duration
|
||||||
BoostTimeout time.Duration
|
BoostTimeout time.Duration
|
||||||
BoostWorkers int
|
BoostWorkers int
|
||||||
@ -53,6 +54,7 @@ func CreateQueue(name string, handle queue.HandlerFunc, exemplar interface{}) qu
|
|||||||
opts["DBIndex"] = q.DBIndex
|
opts["DBIndex"] = q.DBIndex
|
||||||
opts["QueueName"] = q.QueueName
|
opts["QueueName"] = q.QueueName
|
||||||
opts["Workers"] = q.Workers
|
opts["Workers"] = q.Workers
|
||||||
|
opts["MaxWorkers"] = q.MaxWorkers
|
||||||
opts["BlockTimeout"] = q.BlockTimeout
|
opts["BlockTimeout"] = q.BlockTimeout
|
||||||
opts["BoostTimeout"] = q.BoostTimeout
|
opts["BoostTimeout"] = q.BoostTimeout
|
||||||
opts["BoostWorkers"] = q.BoostWorkers
|
opts["BoostWorkers"] = q.BoostWorkers
|
||||||
@ -108,6 +110,7 @@ func getQueueSettings(name string) queueSettings {
|
|||||||
q.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Queue.MaxAttempts)
|
q.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Queue.MaxAttempts)
|
||||||
q.Timeout = sec.Key("TIMEOUT").MustDuration(Queue.Timeout)
|
q.Timeout = sec.Key("TIMEOUT").MustDuration(Queue.Timeout)
|
||||||
q.Workers = sec.Key("WORKERS").MustInt(Queue.Workers)
|
q.Workers = sec.Key("WORKERS").MustInt(Queue.Workers)
|
||||||
|
q.MaxWorkers = sec.Key("MAX_WORKERS").MustInt(Queue.MaxWorkers)
|
||||||
q.BlockTimeout = sec.Key("BLOCK_TIMEOUT").MustDuration(Queue.BlockTimeout)
|
q.BlockTimeout = sec.Key("BLOCK_TIMEOUT").MustDuration(Queue.BlockTimeout)
|
||||||
q.BoostTimeout = sec.Key("BOOST_TIMEOUT").MustDuration(Queue.BoostTimeout)
|
q.BoostTimeout = sec.Key("BOOST_TIMEOUT").MustDuration(Queue.BoostTimeout)
|
||||||
q.BoostWorkers = sec.Key("BOOST_WORKERS").MustInt(Queue.BoostWorkers)
|
q.BoostWorkers = sec.Key("BOOST_WORKERS").MustInt(Queue.BoostWorkers)
|
||||||
@ -135,6 +138,7 @@ func NewQueueService() {
|
|||||||
Queue.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(10)
|
Queue.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(10)
|
||||||
Queue.Timeout = sec.Key("TIMEOUT").MustDuration(GracefulHammerTime + 30*time.Second)
|
Queue.Timeout = sec.Key("TIMEOUT").MustDuration(GracefulHammerTime + 30*time.Second)
|
||||||
Queue.Workers = sec.Key("WORKERS").MustInt(1)
|
Queue.Workers = sec.Key("WORKERS").MustInt(1)
|
||||||
|
Queue.MaxWorkers = sec.Key("MAX_WORKERS").MustInt(10)
|
||||||
Queue.BlockTimeout = sec.Key("BLOCK_TIMEOUT").MustDuration(1 * time.Second)
|
Queue.BlockTimeout = sec.Key("BLOCK_TIMEOUT").MustDuration(1 * time.Second)
|
||||||
Queue.BoostTimeout = sec.Key("BOOST_TIMEOUT").MustDuration(5 * time.Minute)
|
Queue.BoostTimeout = sec.Key("BOOST_TIMEOUT").MustDuration(5 * time.Minute)
|
||||||
Queue.BoostWorkers = sec.Key("BOOST_WORKERS").MustInt(5)
|
Queue.BoostWorkers = sec.Key("BOOST_WORKERS").MustInt(5)
|
||||||
|
@ -1408,7 +1408,7 @@ settings.protect_check_status_contexts_list = Status checks found in the last we
|
|||||||
settings.protect_required_approvals = Required approvals:
|
settings.protect_required_approvals = Required approvals:
|
||||||
settings.protect_required_approvals_desc = Allow only to merge pull request with enough positive reviews.
|
settings.protect_required_approvals_desc = Allow only to merge pull request with enough positive reviews.
|
||||||
settings.protect_approvals_whitelist_enabled = Restrict approvals to whitelisted users or teams
|
settings.protect_approvals_whitelist_enabled = Restrict approvals to whitelisted users or teams
|
||||||
settings.protect_approvals_whitelist_enabled_desc = Only reviews from whitelisted users or teams will count to the required approvals. Without approval whitelist, reviews from anyone with write access count to the required approvals.
|
settings.protect_approvals_whitelist_enabled_desc = Only reviews from whitelisted users or teams will count to the required approvals. Without approval whitelist, reviews from anyone with write access count to the required approvals.
|
||||||
settings.protect_approvals_whitelist_users = Whitelisted reviewers:
|
settings.protect_approvals_whitelist_users = Whitelisted reviewers:
|
||||||
settings.protect_approvals_whitelist_teams = Whitelisted teams for reviews:
|
settings.protect_approvals_whitelist_teams = Whitelisted teams for reviews:
|
||||||
settings.add_protected_branch = Enable protection
|
settings.add_protected_branch = Enable protection
|
||||||
@ -2028,6 +2028,7 @@ monitor.queue.name = Name
|
|||||||
monitor.queue.type = Type
|
monitor.queue.type = Type
|
||||||
monitor.queue.exemplar = Exemplar Type
|
monitor.queue.exemplar = Exemplar Type
|
||||||
monitor.queue.numberworkers = Number of Workers
|
monitor.queue.numberworkers = Number of Workers
|
||||||
|
monitor.queue.maxnumberworkers = Max Number of Workers
|
||||||
monitor.queue.review = Review Config
|
monitor.queue.review = Review Config
|
||||||
monitor.queue.review_add = Review/Add Workers
|
monitor.queue.review_add = Review/Add Workers
|
||||||
monitor.queue.configuration = Initial Configuration
|
monitor.queue.configuration = Initial Configuration
|
||||||
@ -2043,7 +2044,26 @@ monitor.queue.pool.addworkers.numberworkers.placeholder = Number of Workers
|
|||||||
monitor.queue.pool.addworkers.timeout.placeholder = Set to 0 for no timeout
|
monitor.queue.pool.addworkers.timeout.placeholder = Set to 0 for no timeout
|
||||||
monitor.queue.pool.addworkers.mustnumbergreaterzero = Number of Workers to add must be greater than zero
|
monitor.queue.pool.addworkers.mustnumbergreaterzero = Number of Workers to add must be greater than zero
|
||||||
monitor.queue.pool.addworkers.musttimeoutduration = Timeout must be a golang duration eg. 5m or be 0
|
monitor.queue.pool.addworkers.musttimeoutduration = Timeout must be a golang duration eg. 5m or be 0
|
||||||
|
|
||||||
|
monitor.queue.settings.title = Pool Settings
|
||||||
|
monitor.queue.settings.desc = Pools dynamically grow with a boost in response to their worker queue blocking. These changes will not affect current worker groups.
|
||||||
|
monitor.queue.settings.timeout = Boost Timeout
|
||||||
|
monitor.queue.settings.timeout.placeholder = Currently %[1]v
|
||||||
|
monitor.queue.settings.timeout.error = Timeout must be a golang duration eg. 5m or be 0
|
||||||
|
monitor.queue.settings.numberworkers = Boost Number of Workers
|
||||||
|
monitor.queue.settings.numberworkers.placeholder = Currently %[1]d
|
||||||
|
monitor.queue.settings.numberworkers.error = Number of Workers to add must be greater than or equal to zero
|
||||||
|
monitor.queue.settings.maxnumberworkers = Max Number of workers
|
||||||
|
monitor.queue.settings.maxnumberworkers.placeholder = Currently %[1]d
|
||||||
|
monitor.queue.settings.maxnumberworkers.error = Max number of workers must be a number
|
||||||
|
monitor.queue.settings.submit = Change Settings
|
||||||
|
monitor.queue.settings.changed = Settings Updated
|
||||||
|
monitor.queue.settings.blocktimeout = Current Block Timeout
|
||||||
|
monitor.queue.settings.blocktimeout.value = %[1]v
|
||||||
|
|
||||||
|
monitor.queue.pool.none = This queue does not have a Pool
|
||||||
monitor.queue.pool.added = Worker Group Added
|
monitor.queue.pool.added = Worker Group Added
|
||||||
|
monitor.queue.pool.max_changed = Maximum number of workers changed
|
||||||
monitor.queue.pool.workers.title = Active Worker Groups
|
monitor.queue.pool.workers.title = Active Worker Groups
|
||||||
monitor.queue.pool.workers.none = No worker groups.
|
monitor.queue.pool.workers.none = No worker groups.
|
||||||
monitor.queue.pool.cancel = Shutdown Worker Group
|
monitor.queue.pool.cancel = Shutdown Worker Group
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -421,7 +422,74 @@ func AddWorkers(ctx *context.Context) {
|
|||||||
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if desc.Pool == nil {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.monitor.queue.pool.none"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
|
return
|
||||||
|
}
|
||||||
desc.AddWorkers(number, timeout)
|
desc.AddWorkers(number, timeout)
|
||||||
ctx.Flash.Success(ctx.Tr("admin.monitor.queue.pool.added"))
|
ctx.Flash.Success(ctx.Tr("admin.monitor.queue.pool.added"))
|
||||||
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetQueueSettings sets the maximum number of workers for this queue
|
||||||
|
func SetQueueSettings(ctx *context.Context) {
|
||||||
|
qid := ctx.ParamsInt64("qid")
|
||||||
|
desc := queue.GetManager().GetDescription(qid)
|
||||||
|
if desc == nil {
|
||||||
|
ctx.Status(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if desc.Pool == nil {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.monitor.queue.pool.none"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
maxNumberStr := ctx.Query("max-number")
|
||||||
|
numberStr := ctx.Query("number")
|
||||||
|
timeoutStr := ctx.Query("timeout")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var maxNumber, number int
|
||||||
|
var timeout time.Duration
|
||||||
|
if len(maxNumberStr) > 0 {
|
||||||
|
maxNumber, err = strconv.Atoi(maxNumberStr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.maxnumberworkers.error"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if maxNumber < -1 {
|
||||||
|
maxNumber = -1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maxNumber = desc.MaxNumberOfWorkers()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(numberStr) > 0 {
|
||||||
|
number, err = strconv.Atoi(numberStr)
|
||||||
|
if err != nil || number < 0 {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.numberworkers.error"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
number = desc.BoostWorkers()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(timeoutStr) > 0 {
|
||||||
|
timeout, err = time.ParseDuration(timeoutStr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.timeout.error"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeout = desc.Pool.BoostTimeout()
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.SetSettings(maxNumber, number, timeout)
|
||||||
|
ctx.Flash.Success(ctx.Tr("admin.monitor.queue.settings.changed"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/admin/monitor/queue/%d", qid))
|
||||||
|
}
|
||||||
|
@ -416,6 +416,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Post("/cancel/:pid", admin.MonitorCancel)
|
m.Post("/cancel/:pid", admin.MonitorCancel)
|
||||||
m.Group("/queue/:qid", func() {
|
m.Group("/queue/:qid", func() {
|
||||||
m.Get("", admin.Queue)
|
m.Get("", admin.Queue)
|
||||||
|
m.Post("/set", admin.SetQueueSettings)
|
||||||
m.Post("/add", admin.AddWorkers)
|
m.Post("/add", admin.AddWorkers)
|
||||||
m.Post("/cancel/:pid", admin.WorkerCancel)
|
m.Post("/cancel/:pid", admin.WorkerCancel)
|
||||||
})
|
})
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
<th>{{.i18n.Tr "admin.monitor.queue.type"}}</th>
|
<th>{{.i18n.Tr "admin.monitor.queue.type"}}</th>
|
||||||
<th>{{.i18n.Tr "admin.monitor.queue.exemplar"}}</th>
|
<th>{{.i18n.Tr "admin.monitor.queue.exemplar"}}</th>
|
||||||
<th>{{.i18n.Tr "admin.monitor.queue.numberworkers"}}</th>
|
<th>{{.i18n.Tr "admin.monitor.queue.numberworkers"}}</th>
|
||||||
|
<th>{{.i18n.Tr "admin.monitor.queue.maxnumberworkers"}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -22,6 +23,7 @@
|
|||||||
<td>{{.Queue.Type}}</td>
|
<td>{{.Queue.Type}}</td>
|
||||||
<td>{{.Queue.ExemplarType}}</td>
|
<td>{{.Queue.ExemplarType}}</td>
|
||||||
<td>{{$sum := .Queue.NumberOfWorkers}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
<td>{{$sum := .Queue.NumberOfWorkers}}{{if lt $sum 0}}-{{else}}{{$sum}}{{end}}</td>
|
||||||
|
<td>{{if lt $sum 0}}-{{else}}{{.Queue.MaxNumberOfWorkers}}{{end}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -40,6 +42,34 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
<h4 class="ui top attached header">
|
||||||
|
{{.i18n.Tr "admin.monitor.queue.settings.title"}}
|
||||||
|
</h4>
|
||||||
|
<div class="ui attached segment">
|
||||||
|
<p>{{.i18n.Tr "admin.monitor.queue.settings.desc"}}</p>
|
||||||
|
<form method="POST" action="{{.Link}}/set">
|
||||||
|
{{$.CsrfTokenHtml}}
|
||||||
|
<div class="ui form">
|
||||||
|
<div class="inline field">
|
||||||
|
<label for="max-number">{{.i18n.Tr "admin.monitor.queue.settings.maxnumberworkers"}}</label>
|
||||||
|
<input name="max-number" type="text" placeholder="{{.i18n.Tr "admin.monitor.queue.settings.maxnumberworkers.placeholder" .Queue.MaxNumberOfWorkers}}">
|
||||||
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label for="timeout">{{.i18n.Tr "admin.monitor.queue.settings.timeout"}}</label>
|
||||||
|
<input name="timeout" type="text" placeholder="{{.i18n.Tr "admin.monitor.queue.settings.timeout.placeholder" .Queue.BoostTimeout }}">
|
||||||
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label for="number">{{.i18n.Tr "admin.monitor.queue.settings.numberworkers"}}</label>
|
||||||
|
<input name="number" type="text" placeholder="{{.i18n.Tr "admin.monitor.queue.settings.numberworkers.placeholder" .Queue.BoostWorkers}}">
|
||||||
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label>{{.i18n.Tr "admin.monitor.queue.settings.blocktimeout"}}</label>
|
||||||
|
<span>{{.i18n.Tr "admin.monitor.queue.settings.blocktimeout.value" .Queue.BlockTimeout}}</span>
|
||||||
|
</div>
|
||||||
|
<button class="ui submit button">{{.i18n.Tr "admin.monitor.queue.settings.submit"}}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "admin.monitor.queue.pool.addworkers.title"}}
|
{{.i18n.Tr "admin.monitor.queue.pool.addworkers.title"}}
|
||||||
</h4>
|
</h4>
|
||||||
|
Loading…
Reference in New Issue
Block a user