2
0
mirror of https://github.com/hibiken/asynq.git synced 2024-11-10 11:31:58 +08:00

Record deadline within WorkerInfo

This commit is contained in:
Ken Hibino 2021-01-27 15:55:43 -08:00
parent bfde0b6283
commit eba7c4e085
9 changed files with 40 additions and 30 deletions

View File

@ -38,13 +38,13 @@ type heartbeater struct {
// heartbeater goroutine. In other words, confine these variables // heartbeater goroutine. In other words, confine these variables
// to this goroutine only. // to this goroutine only.
started time.Time started time.Time
workers map[string]workerStat workers map[string]*workerInfo
// status is shared with other goroutine but is concurrency safe. // status is shared with other goroutine but is concurrency safe.
status *base.ServerStatus status *base.ServerStatus
// channels to receive updates on active workers. // channels to receive updates on active workers.
starting <-chan *base.TaskMessage starting <-chan *workerInfo
finished <-chan *base.TaskMessage finished <-chan *base.TaskMessage
} }
@ -56,7 +56,7 @@ type heartbeaterParams struct {
queues map[string]int queues map[string]int
strictPriority bool strictPriority bool
status *base.ServerStatus status *base.ServerStatus
starting <-chan *base.TaskMessage starting <-chan *workerInfo
finished <-chan *base.TaskMessage finished <-chan *base.TaskMessage
} }
@ -80,7 +80,7 @@ func newHeartbeater(params heartbeaterParams) *heartbeater {
strictPriority: params.strictPriority, strictPriority: params.strictPriority,
status: params.status, status: params.status,
workers: make(map[string]workerStat), workers: make(map[string]*workerInfo),
starting: params.starting, starting: params.starting,
finished: params.finished, finished: params.finished,
} }
@ -92,11 +92,14 @@ func (h *heartbeater) terminate() {
h.done <- struct{}{} h.done <- struct{}{}
} }
// A workerStat records the message a worker is working on // A workerInfo holds an active worker information.
// and the time the worker has started processing the message. type workerInfo struct {
type workerStat struct { // the task message the worker is processing.
started time.Time
msg *base.TaskMessage msg *base.TaskMessage
// the time the worker has started processing the message.
started time.Time
// deadline the worker has to finish processing the task by.
deadline time.Time
} }
func (h *heartbeater) start(wg *sync.WaitGroup) { func (h *heartbeater) start(wg *sync.WaitGroup) {
@ -121,8 +124,8 @@ func (h *heartbeater) start(wg *sync.WaitGroup) {
h.beat() h.beat()
timer.Reset(h.interval) timer.Reset(h.interval)
case msg := <-h.starting: case w := <-h.starting:
h.workers[msg.ID.String()] = workerStat{time.Now(), msg} h.workers[w.msg.ID.String()] = w
case msg := <-h.finished: case msg := <-h.finished:
delete(h.workers, msg.ID.String()) delete(h.workers, msg.ID.String())
@ -145,16 +148,17 @@ func (h *heartbeater) beat() {
} }
var ws []*base.WorkerInfo var ws []*base.WorkerInfo
for id, stat := range h.workers { for id, w := range h.workers {
ws = append(ws, &base.WorkerInfo{ ws = append(ws, &base.WorkerInfo{
Host: h.host, Host: h.host,
PID: h.pid, PID: h.pid,
ServerID: h.serverID, ServerID: h.serverID,
ID: id, ID: id,
Type: stat.msg.Type, Type: w.msg.Type,
Queue: stat.msg.Queue, Queue: w.msg.Queue,
Payload: stat.msg.Payload, Payload: w.msg.Payload,
Started: stat.started, Started: w.started,
Deadline: w.deadline,
}) })
} }

View File

@ -47,7 +47,7 @@ func TestHeartbeater(t *testing.T) {
queues: tc.queues, queues: tc.queues,
strictPriority: false, strictPriority: false,
status: status, status: status,
starting: make(chan *base.TaskMessage), starting: make(chan *workerInfo),
finished: make(chan *base.TaskMessage), finished: make(chan *base.TaskMessage),
}) })
@ -139,7 +139,7 @@ func TestHeartbeaterWithRedisDown(t *testing.T) {
queues: map[string]int{"default": 1}, queues: map[string]int{"default": 1},
strictPriority: false, strictPriority: false,
status: base.NewServerStatus(base.StatusRunning), status: base.NewServerStatus(base.StatusRunning),
starting: make(chan *base.TaskMessage), starting: make(chan *workerInfo),
finished: make(chan *base.TaskMessage), finished: make(chan *base.TaskMessage),
}) })

View File

@ -726,6 +726,7 @@ func (i *Inspector) Servers() ([]*ServerInfo, error) {
} }
wrkInfo := &WorkerInfo{ wrkInfo := &WorkerInfo{
Started: w.Started, Started: w.Started,
Deadline: w.Deadline,
Task: &ActiveTask{ Task: &ActiveTask{
Task: NewTask(w.Type, w.Payload), Task: NewTask(w.Type, w.Payload),
ID: w.ID, ID: w.ID,
@ -771,6 +772,8 @@ type WorkerInfo struct {
Task *ActiveTask Task *ActiveTask
// Time the worker started processing the task. // Time the worker started processing the task.
Started time.Time Started time.Time
// Time the worker needs to finish processing the task by.
Deadline time.Time
} }
// ClusterKeySlot returns an integer identifying the hash slot the given queue hashes to. // ClusterKeySlot returns an integer identifying the hash slot the given queue hashes to.

View File

@ -283,6 +283,7 @@ type WorkerInfo struct {
Queue string Queue string
Payload map[string]interface{} Payload map[string]interface{}
Started time.Time Started time.Time
Deadline time.Time
} }
// SchedulerEntry holds information about a periodic task registered with a scheduler. // SchedulerEntry holds information about a periodic task registered with a scheduler.

View File

@ -974,7 +974,6 @@ func (r *RDB) ListWorkers() ([]*base.WorkerInfo, error) {
continue // skip bad data continue // skip bad data
} }
workers = append(workers, &w) workers = append(workers, &w)
} }
} }
return workers, nil return workers, nil

View File

@ -2966,6 +2966,7 @@ func TestListWorkers(t *testing.T) {
Queue: m1.Queue, Queue: m1.Queue,
Payload: m1.Payload, Payload: m1.Payload,
Started: time.Now().Add(-1 * time.Second), Started: time.Now().Add(-1 * time.Second),
Deadline: time.Now().Add(30 * time.Second),
}, },
{ {
Host: host, Host: host,
@ -2976,6 +2977,7 @@ func TestListWorkers(t *testing.T) {
Queue: m2.Queue, Queue: m2.Queue,
Payload: m2.Payload, Payload: m2.Payload,
Started: time.Now().Add(-5 * time.Second), Started: time.Now().Add(-5 * time.Second),
Deadline: time.Now().Add(10 * time.Minute),
}, },
{ {
Host: host, Host: host,
@ -2986,6 +2988,7 @@ func TestListWorkers(t *testing.T) {
Queue: m3.Queue, Queue: m3.Queue,
Payload: m3.Payload, Payload: m3.Payload,
Started: time.Now().Add(-30 * time.Second), Started: time.Now().Add(-30 * time.Second),
Deadline: time.Now().Add(30 * time.Minute),
}, },
}, },
}, },

View File

@ -63,7 +63,7 @@ type processor struct {
// cancelations is a set of cancel functions for all active tasks. // cancelations is a set of cancel functions for all active tasks.
cancelations *base.Cancelations cancelations *base.Cancelations
starting chan<- *base.TaskMessage starting chan<- *workerInfo
finished chan<- *base.TaskMessage finished chan<- *base.TaskMessage
} }
@ -78,7 +78,7 @@ type processorParams struct {
strictPriority bool strictPriority bool
errHandler ErrorHandler errHandler ErrorHandler
shutdownTimeout time.Duration shutdownTimeout time.Duration
starting chan<- *base.TaskMessage starting chan<- *workerInfo
finished chan<- *base.TaskMessage finished chan<- *base.TaskMessage
} }
@ -180,7 +180,7 @@ func (p *processor) exec() {
return return
} }
p.starting <- msg p.starting <- &workerInfo{msg, time.Now(), deadline}
go func() { go func() {
defer func() { defer func() {
p.finished <- msg p.finished <- msg

View File

@ -20,7 +20,7 @@ import (
) )
// fakeHeartbeater receives from starting and finished channels and do nothing. // fakeHeartbeater receives from starting and finished channels and do nothing.
func fakeHeartbeater(starting, finished <-chan *base.TaskMessage, done <-chan struct{}) { func fakeHeartbeater(starting <-chan *workerInfo, finished <-chan *base.TaskMessage, done <-chan struct{}) {
for { for {
select { select {
case <-starting: case <-starting:
@ -86,7 +86,7 @@ func TestProcessorSuccessWithSingleQueue(t *testing.T) {
processed = append(processed, task) processed = append(processed, task)
return nil return nil
} }
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
syncCh := make(chan *syncRequest) syncCh := make(chan *syncRequest)
done := make(chan struct{}) done := make(chan struct{})
@ -177,7 +177,7 @@ func TestProcessorSuccessWithMultipleQueues(t *testing.T) {
processed = append(processed, task) processed = append(processed, task)
return nil return nil
} }
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
syncCh := make(chan *syncRequest) syncCh := make(chan *syncRequest)
done := make(chan struct{}) done := make(chan struct{})
@ -258,7 +258,7 @@ func TestProcessTasksWithLargeNumberInPayload(t *testing.T) {
processed = append(processed, task) processed = append(processed, task)
return nil return nil
} }
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
syncCh := make(chan *syncRequest) syncCh := make(chan *syncRequest)
done := make(chan struct{}) done := make(chan struct{})
@ -389,7 +389,7 @@ func TestProcessorRetry(t *testing.T) {
defer mu.Unlock() defer mu.Unlock()
n++ n++
} }
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
done := make(chan struct{}) done := make(chan struct{})
defer func() { close(done) }() defer func() { close(done) }()
@ -470,7 +470,7 @@ func TestProcessorQueues(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
done := make(chan struct{}) done := make(chan struct{})
defer func() { close(done) }() defer func() { close(done) }()
@ -559,7 +559,7 @@ func TestProcessorWithStrictPriority(t *testing.T) {
"critical": 3, "critical": 3,
"low": 1, "low": 1,
} }
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
syncCh := make(chan *syncRequest) syncCh := make(chan *syncRequest)
done := make(chan struct{}) done := make(chan struct{})

View File

@ -316,7 +316,7 @@ func NewServer(r RedisConnOpt, cfg Config) *Server {
logger.SetLevel(toInternalLogLevel(loglevel)) logger.SetLevel(toInternalLogLevel(loglevel))
rdb := rdb.NewRDB(createRedisClient(r)) rdb := rdb.NewRDB(createRedisClient(r))
starting := make(chan *base.TaskMessage) starting := make(chan *workerInfo)
finished := make(chan *base.TaskMessage) finished := make(chan *base.TaskMessage)
syncCh := make(chan *syncRequest) syncCh := make(chan *syncRequest)
status := base.NewServerStatus(base.StatusIdle) status := base.NewServerStatus(base.StatusIdle)