2
0
mirror of https://github.com/hibiken/asynq.git synced 2024-09-20 02:55:54 +08:00

Update Client.Enqueue to return TaskInfo

This commit is contained in:
Ken Hibino 2021-05-15 06:43:18 -07:00
parent 09cbea66f6
commit b835090ad8
6 changed files with 212 additions and 173 deletions

View File

@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Server` API has changed. Renamed `Quiet` to `Stop`. Renamed `Stop` to `Shutdown`. _Note:_ As a result of this renaming, the behavior of `Stop` has changed. Please update the exising code to call `Shutdown` where it used to call `Stop`. - `Server` API has changed. Renamed `Quiet` to `Stop`. Renamed `Stop` to `Shutdown`. _Note:_ As a result of this renaming, the behavior of `Stop` has changed. Please update the exising code to call `Shutdown` where it used to call `Stop`.
- `Scheduler` API has changed. Renamed `Stop` to `Shutdown`. - `Scheduler` API has changed. Renamed `Stop` to `Shutdown`.
- Requires redis v4.0+ for multiple field/value pair support - Requires redis v4.0+ for multiple field/value pair support
- Renamed pending key (TODO: need migration script)
- `Client.Enqueue` now returns `TaskInfo`
- Renamed pending key (TODO: need migration script - Renamed pending key (TODO: need migration script
## [0.17.2] - 2021-06-06 ## [0.17.2] - 2021-06-06

View File

@ -177,11 +177,11 @@ func main() {
if err != nil { if err != nil {
log.Fatalf("could not create task: %v", err) log.Fatalf("could not create task: %v", err)
} }
res, err := c.Enqueue(t) info, err := c.Enqueue(t)
if err != nil { if err != nil {
log.Fatalf("could not enqueue task: %v", err) log.Fatalf("could not enqueue task: %v", err)
} }
fmt.Printf("Enqueued Result: %+v\n", res) fmt.Printf("enqueued task: id=%s queue=%s\n", info.ID(), info.Queue())
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -189,11 +189,11 @@ func main() {
// Use ProcessIn or ProcessAt option. // Use ProcessIn or ProcessAt option.
// ------------------------------------------------------------ // ------------------------------------------------------------
res, err = c.Enqueue(t, asynq.ProcessIn(24*time.Hour)) info, err = c.Enqueue(t, asynq.ProcessIn(24*time.Hour))
if err != nil { if err != nil {
log.Fatalf("could not schedule task: %v", err) log.Fatalf("could not schedule task: %v", err)
} }
fmt.Printf("Enqueued Result: %+v\n", res) fmt.Printf("enqueued task: id=%s queue=%s\n", info.ID(), info.Queue())
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -207,22 +207,22 @@ func main() {
if err != nil { if err != nil {
log.Fatalf("could not create task: %v", err) log.Fatalf("could not create task: %v", err)
} }
res, err = c.Enqueue(t) info, err = c.Enqueue(t)
if err != nil { if err != nil {
log.Fatalf("could not enqueue task: %v", err) log.Fatalf("could not enqueue task: %v", err)
} }
fmt.Printf("Enqueued Result: %+v\n", res) fmt.Printf("enqueued task: id=%s queue=%s\n", info.ID(), info.Queue())
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Example 4: Pass options to tune task processing behavior at enqueue time. // Example 4: Pass options to tune task processing behavior at enqueue time.
// Options passed at enqueue time override default ones. // Options passed at enqueue time override default ones.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
res, err = c.Enqueue(t, asynq.Queue("critical"), asynq.Timeout(30*time.Second)) info, err = c.Enqueue(t, asynq.Queue("critical"), asynq.Timeout(30*time.Second))
if err != nil { if err != nil {
log.Fatal("could not enqueue task: %v", err) log.Fatal("could not enqueue task: %v", err)
} }
fmt.Printf("Enqueued Result: %+v\n", res) fmt.Printf("enqueued task: id=%s queue=%s\n", info.ID(), info.Queue())
} }
``` ```

View File

@ -254,41 +254,6 @@ func (c *Client) SetDefaultOptions(taskType string, opts ...Option) {
c.opts[taskType] = opts c.opts[taskType] = opts
} }
// A Result holds enqueued task's metadata.
type Result struct {
// ID is a unique identifier for the task.
ID string
// EnqueuedAt is the time the task was enqueued in UTC.
EnqueuedAt time.Time
// ProcessAt indicates when the task should be processed.
ProcessAt time.Time
// Retry is the maximum number of retry for the task.
Retry int
// Queue is a name of the queue the task is enqueued to.
Queue string
// Timeout is the timeout value for the task.
// Counting for timeout starts when a worker starts processing the task.
// If task processing doesn't complete within the timeout, the task will be retried.
// The value zero means no timeout.
//
// If deadline is set, min(now+timeout, deadline) is used, where the now is the time when
// a worker starts processing the task.
Timeout time.Duration
// Deadline is the deadline value for the task.
// If task processing doesn't complete before the deadline, the task will be retried.
// The value time.Unix(0, 0) means no deadline.
//
// If timeout is set, min(now+timeout, deadline) is used, where the now is the time when
// a worker starts processing the task.
Deadline time.Time
}
// Close closes the connection with redis. // Close closes the connection with redis.
func (c *Client) Close() error { func (c *Client) Close() error {
return c.rdb.Close() return c.rdb.Close()
@ -296,13 +261,14 @@ func (c *Client) Close() error {
// Enqueue enqueues the given task to be processed asynchronously. // Enqueue enqueues the given task to be processed asynchronously.
// //
// Enqueue returns nil if the task is enqueued successfully, otherwise returns a non-nil error. // Enqueue returns TaskInfo and nil error if the task is enqueued successfully, otherwise returns a non-nil error.
// //
// The argument opts specifies the behavior of task processing. // The argument opts specifies the behavior of task processing.
// If there are conflicting Option values the last one overrides others. // If there are conflicting Option values the last one overrides others.
// By deafult, max retry is set to 25 and timeout is set to 30 minutes. // By deafult, max retry is set to 25 and timeout is set to 30 minutes.
// If no ProcessAt or ProcessIn options are passed, the task will be processed immediately. //
func (c *Client) Enqueue(task *Task, opts ...Option) (*Result, error) { // If no ProcessAt or ProcessIn options are provided, the task will be pending immediately.
func (c *Client) Enqueue(task *Task, opts ...Option) (*TaskInfo, error) {
c.mu.Lock() c.mu.Lock()
if defaults, ok := c.opts[task.Type()]; ok { if defaults, ok := c.opts[task.Type()]; ok {
opts = append(defaults, opts...) opts = append(defaults, opts...)
@ -339,11 +305,14 @@ func (c *Client) Enqueue(task *Task, opts ...Option) (*Result, error) {
UniqueKey: uniqueKey, UniqueKey: uniqueKey,
} }
now := time.Now() now := time.Now()
var state base.TaskState
if opt.processAt.Before(now) || opt.processAt.Equal(now) { if opt.processAt.Before(now) || opt.processAt.Equal(now) {
opt.processAt = now opt.processAt = now
err = c.enqueue(msg, opt.uniqueTTL) err = c.enqueue(msg, opt.uniqueTTL)
state = base.TaskStatePending
} else { } else {
err = c.schedule(msg, opt.processAt, opt.uniqueTTL) err = c.schedule(msg, opt.processAt, opt.uniqueTTL)
state = base.TaskStateScheduled
} }
switch { switch {
case errors.Is(err, errors.ErrDuplicateTask): case errors.Is(err, errors.ErrDuplicateTask):
@ -351,15 +320,7 @@ func (c *Client) Enqueue(task *Task, opts ...Option) (*Result, error) {
case err != nil: case err != nil:
return nil, err return nil, err
} }
return &Result{ return &TaskInfo{msg, state, opt.processAt}, nil
ID: msg.ID.String(),
EnqueuedAt: time.Now().UTC(),
ProcessAt: opt.processAt,
Queue: msg.Queue,
Retry: msg.Retry,
Timeout: timeout,
Deadline: deadline,
}, nil
} }
func (c *Client) enqueue(msg *base.TaskMessage, uniqueTTL time.Duration) error { func (c *Client) enqueue(msg *base.TaskMessage, uniqueTTL time.Duration) error {

View File

@ -32,7 +32,7 @@ func TestClientEnqueueWithProcessAtOption(t *testing.T) {
task *Task task *Task
processAt time.Time // value for ProcessAt option processAt time.Time // value for ProcessAt option
opts []Option // other options opts []Option // other options
wantRes *Result wantInfo *TaskInfo
wantPending map[string][]*base.TaskMessage wantPending map[string][]*base.TaskMessage
wantScheduled map[string][]base.Z wantScheduled map[string][]base.Z
}{ }{
@ -41,13 +41,16 @@ func TestClientEnqueueWithProcessAtOption(t *testing.T) {
task: task, task: task,
processAt: now, processAt: now,
opts: []Option{}, opts: []Option{},
wantRes: &Result{ wantInfo: &TaskInfo{
EnqueuedAt: now.UTC(), msg: &base.TaskMessage{
ProcessAt: now, Type: task.Type(),
Payload: task.Payload(),
Queue: "default", Queue: "default",
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline, },
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -70,13 +73,17 @@ func TestClientEnqueueWithProcessAtOption(t *testing.T) {
task: task, task: task,
processAt: oneHourLater, processAt: oneHourLater,
opts: []Option{}, opts: []Option{},
wantRes: &Result{ wantInfo: &TaskInfo{
EnqueuedAt: now.UTC(), msg: &base.TaskMessage{
ProcessAt: oneHourLater, Type: task.Type(),
Queue: "default", Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Queue: "default",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStateScheduled,
nextProcessAt: oneHourLater,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": {}, "default": {},
@ -103,18 +110,19 @@ func TestClientEnqueueWithProcessAtOption(t *testing.T) {
h.FlushDB(t, r) // clean up db before each test case. h.FlushDB(t, r) // clean up db before each test case.
opts := append(tc.opts, ProcessAt(tc.processAt)) opts := append(tc.opts, ProcessAt(tc.processAt))
gotRes, err := client.Enqueue(tc.task, opts...) gotInfo, err := client.Enqueue(tc.task, opts...)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue continue
} }
cmpOptions := []cmp.Option{ cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(Result{}, "ID"), cmp.AllowUnexported(TaskInfo{}),
cmpopts.IgnoreFields(base.TaskMessage{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond), cmpopts.EquateApproxTime(500 * time.Millisecond),
} }
if diff := cmp.Diff(tc.wantRes, gotRes, cmpOptions...); diff != "" { if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task, ProcessAt(%v)) returned %v, want %v; (-want,+got)\n%s", t.Errorf("%s;\nEnqueue(task, ProcessAt(%v)) returned %v, want %v; (-want,+got)\n%s",
tc.desc, tc.processAt, gotRes, tc.wantRes, diff) tc.desc, tc.processAt, gotInfo, tc.wantInfo, diff)
} }
for qname, want := range tc.wantPending { for qname, want := range tc.wantPending {
@ -144,7 +152,7 @@ func TestClientEnqueue(t *testing.T) {
desc string desc string
task *Task task *Task
opts []Option opts []Option
wantRes *Result wantInfo *TaskInfo
wantPending map[string][]*base.TaskMessage wantPending map[string][]*base.TaskMessage
}{ }{
{ {
@ -153,12 +161,17 @@ func TestClientEnqueue(t *testing.T) {
opts: []Option{ opts: []Option{
MaxRetry(3), MaxRetry(3),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "default", Type: task.Type(),
Payload: task.Payload(),
Retry: 3, Retry: 3,
Timeout: defaultTimeout, Queue: "default",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -179,12 +192,17 @@ func TestClientEnqueue(t *testing.T) {
opts: []Option{ opts: []Option{
MaxRetry(-2), MaxRetry(-2),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Type: task.Type(),
Payload: task.Payload(),
Retry: 0, // Retry count should be set to zero
Queue: "default", Queue: "default",
Retry: 0, Timeout: int64(defaultTimeout.Seconds()),
Timeout: defaultTimeout, Deadline: noDeadline.Unix(),
Deadline: noDeadline, },
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -206,12 +224,17 @@ func TestClientEnqueue(t *testing.T) {
MaxRetry(2), MaxRetry(2),
MaxRetry(10), MaxRetry(10),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Type: task.Type(),
Payload: task.Payload(),
Retry: 10, // Last option takes precedence
Queue: "default", Queue: "default",
Retry: 10, Timeout: int64(defaultTimeout.Seconds()),
Timeout: defaultTimeout, Deadline: noDeadline.Unix(),
Deadline: noDeadline, },
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -232,12 +255,17 @@ func TestClientEnqueue(t *testing.T) {
opts: []Option{ opts: []Option{
Queue("custom"), Queue("custom"),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "custom", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Queue: "custom",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"custom": { "custom": {
@ -258,12 +286,17 @@ func TestClientEnqueue(t *testing.T) {
opts: []Option{ opts: []Option{
Queue("HIGH"), Queue("HIGH"),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "high", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Queue: "high",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"high": { "high": {
@ -284,12 +317,17 @@ func TestClientEnqueue(t *testing.T) {
opts: []Option{ opts: []Option{
Timeout(20 * time.Second), Timeout(20 * time.Second),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "default", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: 20 * time.Second, Queue: "default",
Deadline: noDeadline, Timeout: 20,
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -310,12 +348,17 @@ func TestClientEnqueue(t *testing.T) {
opts: []Option{ opts: []Option{
Deadline(time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC)), Deadline(time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC)),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "default", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: noTimeout, Queue: "default",
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC), Timeout: int64(noTimeout.Seconds()),
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC).Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -337,12 +380,17 @@ func TestClientEnqueue(t *testing.T) {
Timeout(20 * time.Second), Timeout(20 * time.Second),
Deadline(time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC)), Deadline(time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC)),
}, },
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "default", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: 20 * time.Second, Queue: "default",
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC), Timeout: 20,
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC).Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -362,18 +410,19 @@ func TestClientEnqueue(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case. h.FlushDB(t, r) // clean up db before each test case.
gotRes, err := client.Enqueue(tc.task, tc.opts...) gotInfo, err := client.Enqueue(tc.task, tc.opts...)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue continue
} }
cmpOptions := []cmp.Option{ cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(Result{}, "ID", "EnqueuedAt"), cmp.AllowUnexported(TaskInfo{}),
cmpopts.IgnoreFields(base.TaskMessage{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond), cmpopts.EquateApproxTime(500 * time.Millisecond),
} }
if diff := cmp.Diff(tc.wantRes, gotRes, cmpOptions...); diff != "" { if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task) returned %v, want %v; (-want,+got)\n%s", t.Errorf("%s;\nEnqueue(task) returned %v, want %v; (-want,+got)\n%s",
tc.desc, gotRes, tc.wantRes, diff) tc.desc, gotInfo, tc.wantInfo, diff)
} }
for qname, want := range tc.wantPending { for qname, want := range tc.wantPending {
@ -398,7 +447,7 @@ func TestClientEnqueueWithProcessInOption(t *testing.T) {
task *Task task *Task
delay time.Duration // value for ProcessIn option delay time.Duration // value for ProcessIn option
opts []Option // other options opts []Option // other options
wantRes *Result wantInfo *TaskInfo
wantPending map[string][]*base.TaskMessage wantPending map[string][]*base.TaskMessage
wantScheduled map[string][]base.Z wantScheduled map[string][]base.Z
}{ }{
@ -407,12 +456,17 @@ func TestClientEnqueueWithProcessInOption(t *testing.T) {
task: task, task: task,
delay: 1 * time.Hour, delay: 1 * time.Hour,
opts: []Option{}, opts: []Option{},
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now.Add(1 * time.Hour), msg: &base.TaskMessage{
Queue: "default", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Queue: "default",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStateScheduled,
nextProcessAt: time.Now().Add(1 * time.Hour),
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": {}, "default": {},
@ -438,12 +492,17 @@ func TestClientEnqueueWithProcessInOption(t *testing.T) {
task: task, task: task,
delay: 0, delay: 0,
opts: []Option{}, opts: []Option{},
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "default", Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Queue: "default",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
wantPending: map[string][]*base.TaskMessage{ wantPending: map[string][]*base.TaskMessage{
"default": { "default": {
@ -467,18 +526,19 @@ func TestClientEnqueueWithProcessInOption(t *testing.T) {
h.FlushDB(t, r) // clean up db before each test case. h.FlushDB(t, r) // clean up db before each test case.
opts := append(tc.opts, ProcessIn(tc.delay)) opts := append(tc.opts, ProcessIn(tc.delay))
gotRes, err := client.Enqueue(tc.task, opts...) gotInfo, err := client.Enqueue(tc.task, opts...)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue continue
} }
cmpOptions := []cmp.Option{ cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(Result{}, "ID", "EnqueuedAt"), cmp.AllowUnexported(TaskInfo{}),
cmpopts.IgnoreFields(base.TaskMessage{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond), cmpopts.EquateApproxTime(500 * time.Millisecond),
} }
if diff := cmp.Diff(tc.wantRes, gotRes, cmpOptions...); diff != "" { if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task, ProcessIn(%v)) returned %v, want %v; (-want,+got)\n%s", t.Errorf("%s;\nEnqueue(task, ProcessIn(%v)) returned %v, want %v; (-want,+got)\n%s",
tc.desc, tc.delay, gotRes, tc.wantRes, diff) tc.desc, tc.delay, gotInfo, tc.wantInfo, diff)
} }
for qname, want := range tc.wantPending { for qname, want := range tc.wantPending {
@ -537,7 +597,7 @@ func TestClientDefaultOptions(t *testing.T) {
defaultOpts []Option // options set at the client level. defaultOpts []Option // options set at the client level.
opts []Option // options used at enqueue time. opts []Option // options used at enqueue time.
task *Task task *Task
wantRes *Result wantInfo *TaskInfo
queue string // queue that the message should go into. queue string // queue that the message should go into.
want *base.TaskMessage want *base.TaskMessage
}{ }{
@ -546,12 +606,17 @@ func TestClientDefaultOptions(t *testing.T) {
defaultOpts: []Option{Queue("feed")}, defaultOpts: []Option{Queue("feed")},
opts: []Option{}, opts: []Option{},
task: NewTask("feed:import", nil), task: NewTask("feed:import", nil),
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "feed", Type: "feed:import",
Payload: nil,
Retry: defaultMaxRetry, Retry: defaultMaxRetry,
Timeout: defaultTimeout, Queue: "feed",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
queue: "feed", queue: "feed",
want: &base.TaskMessage{ want: &base.TaskMessage{
@ -568,12 +633,17 @@ func TestClientDefaultOptions(t *testing.T) {
defaultOpts: []Option{Queue("feed"), MaxRetry(5)}, defaultOpts: []Option{Queue("feed"), MaxRetry(5)},
opts: []Option{}, opts: []Option{},
task: NewTask("feed:import", nil), task: NewTask("feed:import", nil),
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "feed", Type: "feed:import",
Payload: nil,
Retry: 5, Retry: 5,
Timeout: defaultTimeout, Queue: "feed",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
queue: "feed", queue: "feed",
want: &base.TaskMessage{ want: &base.TaskMessage{
@ -590,12 +660,17 @@ func TestClientDefaultOptions(t *testing.T) {
defaultOpts: []Option{Queue("feed"), MaxRetry(5)}, defaultOpts: []Option{Queue("feed"), MaxRetry(5)},
opts: []Option{Queue("critical")}, opts: []Option{Queue("critical")},
task: NewTask("feed:import", nil), task: NewTask("feed:import", nil),
wantRes: &Result{ wantInfo: &TaskInfo{
ProcessAt: now, msg: &base.TaskMessage{
Queue: "critical", Type: "feed:import",
Payload: nil,
Retry: 5, Retry: 5,
Timeout: defaultTimeout, Queue: "critical",
Deadline: noDeadline, Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
state: base.TaskStatePending,
nextProcessAt: now,
}, },
queue: "critical", queue: "critical",
want: &base.TaskMessage{ want: &base.TaskMessage{
@ -614,17 +689,18 @@ func TestClientDefaultOptions(t *testing.T) {
c := NewClient(getRedisConnOpt(t)) c := NewClient(getRedisConnOpt(t))
defer c.Close() defer c.Close()
c.SetDefaultOptions(tc.task.Type(), tc.defaultOpts...) c.SetDefaultOptions(tc.task.Type(), tc.defaultOpts...)
gotRes, err := c.Enqueue(tc.task, tc.opts...) gotInfo, err := c.Enqueue(tc.task, tc.opts...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
cmpOptions := []cmp.Option{ cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(Result{}, "ID", "EnqueuedAt"), cmp.AllowUnexported(TaskInfo{}),
cmpopts.IgnoreFields(base.TaskMessage{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond), cmpopts.EquateApproxTime(500 * time.Millisecond),
} }
if diff := cmp.Diff(tc.wantRes, gotRes, cmpOptions...); diff != "" { if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task, opts...) returned %v, want %v; (-want,+got)\n%s", t.Errorf("%s;\nEnqueue(task, opts...) returned %v, want %v; (-want,+got)\n%s",
tc.desc, gotRes, tc.wantRes, diff) tc.desc, gotInfo, tc.wantInfo, diff)
} }
pending := h.GetPendingMessages(t, r, tc.queue) pending := h.GetPendingMessages(t, r, tc.queue)
if len(pending) != 1 { if len(pending) != 1 {

4
doc.go
View File

@ -29,10 +29,10 @@ The Client is used to enqueue a task.
task := asynq.NewTask("example", b) task := asynq.NewTask("example", b)
// Enqueue the task to be processed immediately. // Enqueue the task to be processed immediately.
res, err := client.Enqueue(task) info, err := client.Enqueue(task)
// Schedule the task to be processed after one minute. // Schedule the task to be processed after one minute.
res, err = client.Enqueue(t, asynq.ProcessIn(1*time.Minute)) info, err = client.Enqueue(t, asynq.ProcessIn(1*time.Minute))
The Server is used to run the task processing workers with a given The Server is used to run the task processing workers with a given
handler. handler.

View File

@ -117,7 +117,7 @@ type enqueueJob struct {
} }
func (j *enqueueJob) Run() { func (j *enqueueJob) Run() {
res, err := j.client.Enqueue(j.task, j.opts...) info, 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 { if j.errHandler != nil {
@ -125,10 +125,10 @@ func (j *enqueueJob) Run() {
} }
return return
} }
j.logger.Debugf("scheduler enqueued a task: %+v", res) j.logger.Debugf("scheduler enqueued a task: %+v", info)
event := &base.SchedulerEnqueueEvent{ event := &base.SchedulerEnqueueEvent{
TaskID: res.ID, TaskID: info.ID(),
EnqueuedAt: res.EnqueuedAt.In(j.location), EnqueuedAt: time.Now().In(j.location),
} }
err = j.rdb.RecordSchedulerEnqueueEvent(j.id.String(), event) err = j.rdb.RecordSchedulerEnqueueEvent(j.id.String(), event)
if err != nil { if err != nil {