mirror of
https://github.com/hibiken/asynq.git
synced 2024-12-26 07:42:17 +08:00
Add EnqueueErrorHandler option to SchedulerOpts
This commit is contained in:
parent
8312515e64
commit
96b2318300
@ -2993,7 +2993,7 @@ func TestWriteListClearSchedulerEntries(t *testing.T) {
|
|||||||
Spec: "* * * * *",
|
Spec: "* * * * *",
|
||||||
Type: "foo",
|
Type: "foo",
|
||||||
Payload: nil,
|
Payload: nil,
|
||||||
Opts: "",
|
Opts: nil,
|
||||||
Next: now.Add(5 * time.Hour),
|
Next: now.Add(5 * time.Hour),
|
||||||
Prev: now.Add(-2 * time.Hour),
|
Prev: now.Add(-2 * time.Hour),
|
||||||
},
|
},
|
||||||
@ -3001,7 +3001,7 @@ func TestWriteListClearSchedulerEntries(t *testing.T) {
|
|||||||
Spec: "@every 20m",
|
Spec: "@every 20m",
|
||||||
Type: "bar",
|
Type: "bar",
|
||||||
Payload: map[string]interface{}{"fiz": "baz"},
|
Payload: map[string]interface{}{"fiz": "baz"},
|
||||||
Opts: "",
|
Opts: nil,
|
||||||
Next: now.Add(1 * time.Minute),
|
Next: now.Add(1 * time.Minute),
|
||||||
Prev: now.Add(-19 * time.Minute),
|
Prev: now.Add(-19 * time.Minute),
|
||||||
},
|
},
|
||||||
|
77
scheduler.go
77
scheduler.go
@ -19,15 +19,16 @@ import (
|
|||||||
|
|
||||||
// A Scheduler kicks off tasks at regular intervals based on the user defined schedule.
|
// A Scheduler kicks off tasks at regular intervals based on the user defined schedule.
|
||||||
type Scheduler struct {
|
type Scheduler struct {
|
||||||
id string
|
id string
|
||||||
status *base.ServerStatus
|
status *base.ServerStatus
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
client *Client
|
client *Client
|
||||||
rdb *rdb.RDB
|
rdb *rdb.RDB
|
||||||
cron *cron.Cron
|
cron *cron.Cron
|
||||||
location *time.Location
|
location *time.Location
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
errHandler func(task *Task, opts []Option, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScheduler returns a new Scheduler instance given the redis connection option.
|
// NewScheduler returns a new Scheduler instance given the redis connection option.
|
||||||
@ -50,14 +51,15 @@ func NewScheduler(r RedisConnOpt, opts *SchedulerOpts) *Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Scheduler{
|
return &Scheduler{
|
||||||
id: generateSchedulerID(),
|
id: generateSchedulerID(),
|
||||||
status: base.NewServerStatus(base.StatusIdle),
|
status: base.NewServerStatus(base.StatusIdle),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
client: NewClient(r),
|
client: NewClient(r),
|
||||||
rdb: rdb.NewRDB(createRedisClient(r)),
|
rdb: rdb.NewRDB(createRedisClient(r)),
|
||||||
cron: cron.New(cron.WithLocation(loc)),
|
cron: cron.New(cron.WithLocation(loc)),
|
||||||
location: loc,
|
location: loc,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
|
errHandler: opts.EnqueueErrorHandler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,25 +88,31 @@ type SchedulerOpts struct {
|
|||||||
// If unset, the UTC time zone (time.UTC) is used.
|
// If unset, the UTC time zone (time.UTC) is used.
|
||||||
Location *time.Location
|
Location *time.Location
|
||||||
|
|
||||||
// TODO: Add ErrorHandler
|
// EnqueueErrorHandler gets called when scheduler cannot enqueue a registered task
|
||||||
|
// due to an error.
|
||||||
|
EnqueueErrorHandler func(task *Task, opts []Option, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// enqueueJob encapsulates the job of enqueing a task and recording the event.
|
// enqueueJob encapsulates the job of enqueing a task and recording the event.
|
||||||
type enqueueJob struct {
|
type enqueueJob struct {
|
||||||
id uuid.UUID
|
id uuid.UUID
|
||||||
cronspec string
|
cronspec string
|
||||||
task *Task
|
task *Task
|
||||||
opts []Option
|
opts []Option
|
||||||
location *time.Location
|
location *time.Location
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
client *Client
|
client *Client
|
||||||
rdb *rdb.RDB
|
rdb *rdb.RDB
|
||||||
|
errHandler func(task *Task, opts []Option, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *enqueueJob) Run() {
|
func (j *enqueueJob) Run() {
|
||||||
res, err := j.client.Enqueue(j.task, j.opts...)
|
res, err := j.client.Enqueue(j.task, j.opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
j.logger.Errorf("scheduler could not enqueue a task %+v: %v", j.task, err)
|
j.logger.Errorf("scheduler could not enqueue a task %+v: %v", j.task, err)
|
||||||
|
if j.errHandler != nil {
|
||||||
|
j.errHandler(j.task, j.opts, err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
j.logger.Infof("scheduler enqueued a task: %+v", res)
|
j.logger.Infof("scheduler enqueued a task: %+v", res)
|
||||||
@ -122,14 +130,15 @@ func (j *enqueueJob) Run() {
|
|||||||
// It returns an ID of the newly registered entry.
|
// It returns an ID of the newly registered entry.
|
||||||
func (s *Scheduler) Register(cronspec string, task *Task, opts ...Option) (entryID string, err error) {
|
func (s *Scheduler) Register(cronspec string, task *Task, opts ...Option) (entryID string, err error) {
|
||||||
job := &enqueueJob{
|
job := &enqueueJob{
|
||||||
id: uuid.New(),
|
id: uuid.New(),
|
||||||
cronspec: cronspec,
|
cronspec: cronspec,
|
||||||
task: task,
|
task: task,
|
||||||
opts: opts,
|
opts: opts,
|
||||||
location: s.location,
|
location: s.location,
|
||||||
client: s.client,
|
client: s.client,
|
||||||
rdb: s.rdb,
|
rdb: s.rdb,
|
||||||
logger: s.logger,
|
logger: s.logger,
|
||||||
|
errHandler: s.errHandler,
|
||||||
}
|
}
|
||||||
if _, err = s.cron.AddJob(cronspec, job); err != nil {
|
if _, err = s.cron.AddJob(cronspec, job); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package asynq
|
package asynq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -76,3 +77,42 @@ func TestScheduler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSchedulerWhenRedisDown(t *testing.T) {
|
||||||
|
var (
|
||||||
|
mu sync.Mutex
|
||||||
|
counter int
|
||||||
|
)
|
||||||
|
errorHandler := func(task *Task, opts []Option, err error) {
|
||||||
|
mu.Lock()
|
||||||
|
counter++
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to non-existent redis instance to simulate a redis server being down.
|
||||||
|
scheduler := NewScheduler(
|
||||||
|
RedisClientOpt{Addr: ":9876"},
|
||||||
|
&SchedulerOpts{EnqueueErrorHandler: errorHandler},
|
||||||
|
)
|
||||||
|
|
||||||
|
task := NewTask("test", nil)
|
||||||
|
|
||||||
|
if _, err := scheduler.Register("@every 3s", task); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scheduler.Start(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Scheduler should attempt to enqueue the task three times (every 3s).
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
if err := scheduler.Stop(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
if counter != 3 {
|
||||||
|
t.Errorf("EnqueueErrorHandler was called %d times, want 3", counter)
|
||||||
|
}
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user