2020-01-03 10:13:16 +08:00
|
|
|
// Copyright 2020 Kentaro Hibino. All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2019-11-30 00:00:43 +08:00
|
|
|
package asynq
|
|
|
|
|
|
|
|
import (
|
2020-10-12 01:06:28 +08:00
|
|
|
"sync"
|
2019-11-30 00:00:43 +08:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/go-cmp/cmp"
|
2022-05-28 01:50:02 +08:00
|
|
|
|
2019-12-22 23:15:45 +08:00
|
|
|
"github.com/hibiken/asynq/internal/base"
|
2022-03-19 22:16:55 +08:00
|
|
|
"github.com/hibiken/asynq/internal/testutil"
|
2019-11-30 00:00:43 +08:00
|
|
|
)
|
|
|
|
|
2020-11-08 02:41:27 +08:00
|
|
|
func TestSchedulerRegister(t *testing.T) {
|
2019-11-30 00:00:43 +08:00
|
|
|
tests := []struct {
|
2020-09-27 08:33:29 +08:00
|
|
|
cronspec string
|
|
|
|
task *Task
|
|
|
|
opts []Option
|
|
|
|
wait time.Duration
|
|
|
|
queue string
|
|
|
|
want []*base.TaskMessage
|
2019-11-30 00:00:43 +08:00
|
|
|
}{
|
|
|
|
{
|
2020-09-27 08:33:29 +08:00
|
|
|
cronspec: "@every 3s",
|
|
|
|
task: NewTask("task1", nil),
|
|
|
|
opts: []Option{MaxRetry(10)},
|
|
|
|
wait: 10 * time.Second,
|
|
|
|
queue: "default",
|
|
|
|
want: []*base.TaskMessage{
|
|
|
|
{
|
|
|
|
Type: "task1",
|
|
|
|
Payload: nil,
|
|
|
|
Retry: 10,
|
|
|
|
Timeout: int64(defaultTimeout.Seconds()),
|
|
|
|
Queue: "default",
|
2020-08-09 22:13:42 +08:00
|
|
|
},
|
2020-09-27 08:33:29 +08:00
|
|
|
{
|
|
|
|
Type: "task1",
|
|
|
|
Payload: nil,
|
|
|
|
Retry: 10,
|
|
|
|
Timeout: int64(defaultTimeout.Seconds()),
|
|
|
|
Queue: "default",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: "task1",
|
|
|
|
Payload: nil,
|
|
|
|
Retry: 10,
|
|
|
|
Timeout: int64(defaultTimeout.Seconds()),
|
|
|
|
Queue: "default",
|
2020-08-09 22:13:42 +08:00
|
|
|
},
|
2019-11-30 00:00:43 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-09-27 08:33:29 +08:00
|
|
|
r := setup(t)
|
|
|
|
|
2019-11-30 00:00:43 +08:00
|
|
|
for _, tc := range tests {
|
2020-09-27 08:33:29 +08:00
|
|
|
scheduler := NewScheduler(getRedisConnOpt(t), nil)
|
|
|
|
if _, err := scheduler.Register(tc.cronspec, tc.task, tc.opts...); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2019-11-30 00:00:43 +08:00
|
|
|
|
2020-09-27 08:33:29 +08:00
|
|
|
if err := scheduler.Start(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2019-11-30 00:00:43 +08:00
|
|
|
time.Sleep(tc.wait)
|
2021-03-23 21:20:54 +08:00
|
|
|
scheduler.Shutdown()
|
2019-11-30 00:00:43 +08:00
|
|
|
|
2022-03-19 22:16:55 +08:00
|
|
|
got := testutil.GetPendingMessages(t, r, tc.queue)
|
|
|
|
if diff := cmp.Diff(tc.want, got, testutil.IgnoreIDOpt); diff != "" {
|
2020-09-27 08:33:29 +08:00
|
|
|
t.Errorf("mismatch found in queue %q: (-want,+got)\n%s", tc.queue, diff)
|
2019-11-30 00:00:43 +08:00
|
|
|
}
|
2020-09-27 08:33:29 +08:00
|
|
|
}
|
|
|
|
}
|
2020-10-12 01:06:28 +08:00
|
|
|
|
|
|
|
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)
|
2021-03-23 21:20:54 +08:00
|
|
|
scheduler.Shutdown()
|
2020-10-12 01:06:28 +08:00
|
|
|
|
|
|
|
mu.Lock()
|
|
|
|
if counter != 3 {
|
|
|
|
t.Errorf("EnqueueErrorHandler was called %d times, want 3", counter)
|
|
|
|
}
|
|
|
|
mu.Unlock()
|
|
|
|
}
|
2020-11-08 02:41:27 +08:00
|
|
|
|
|
|
|
func TestSchedulerUnregister(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
cronspec string
|
|
|
|
task *Task
|
|
|
|
opts []Option
|
|
|
|
wait time.Duration
|
|
|
|
queue string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
cronspec: "@every 3s",
|
|
|
|
task: NewTask("task1", nil),
|
|
|
|
opts: []Option{MaxRetry(10)},
|
|
|
|
wait: 10 * time.Second,
|
|
|
|
queue: "default",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
r := setup(t)
|
|
|
|
|
|
|
|
for _, tc := range tests {
|
|
|
|
scheduler := NewScheduler(getRedisConnOpt(t), nil)
|
|
|
|
entryID, err := scheduler.Register(tc.cronspec, tc.task, tc.opts...)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := scheduler.Unregister(entryID); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := scheduler.Start(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
time.Sleep(tc.wait)
|
2021-03-23 21:20:54 +08:00
|
|
|
scheduler.Shutdown()
|
2020-11-08 02:41:27 +08:00
|
|
|
|
2022-03-19 22:16:55 +08:00
|
|
|
got := testutil.GetPendingMessages(t, r, tc.queue)
|
2020-11-08 02:41:27 +08:00
|
|
|
if len(got) != 0 {
|
|
|
|
t.Errorf("%d tasks were enqueued, want zero", len(got))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-28 01:50:02 +08:00
|
|
|
|
|
|
|
func TestSchedulerPostAndPreEnqueueHandler(t *testing.T) {
|
|
|
|
var (
|
|
|
|
preMu sync.Mutex
|
|
|
|
preCounter int
|
|
|
|
postMu sync.Mutex
|
|
|
|
postCounter int
|
|
|
|
)
|
|
|
|
preHandler := func(task *Task, opts []Option) {
|
|
|
|
preMu.Lock()
|
|
|
|
preCounter++
|
|
|
|
preMu.Unlock()
|
|
|
|
}
|
|
|
|
postHandler := func(info *TaskInfo, err error) {
|
|
|
|
postMu.Lock()
|
|
|
|
postCounter++
|
|
|
|
postMu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect to non-existent redis instance to simulate a redis server being down.
|
|
|
|
scheduler := NewScheduler(
|
|
|
|
getRedisConnOpt(t),
|
|
|
|
&SchedulerOpts{
|
|
|
|
PreEnqueueFunc: preHandler,
|
|
|
|
PostEnqueueFunc: postHandler,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
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)
|
|
|
|
scheduler.Shutdown()
|
|
|
|
|
|
|
|
preMu.Lock()
|
|
|
|
if preCounter != 3 {
|
|
|
|
t.Errorf("PreEnqueueFunc was called %d times, want 3", preCounter)
|
|
|
|
}
|
|
|
|
preMu.Unlock()
|
|
|
|
|
|
|
|
postMu.Lock()
|
|
|
|
if postCounter != 3 {
|
|
|
|
t.Errorf("PostEnqueueFunc was called %d times, want 3", postCounter)
|
|
|
|
}
|
|
|
|
postMu.Unlock()
|
|
|
|
}
|