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-20 13:19:46 +08:00
|
|
|
package asynq
|
|
|
|
|
|
|
|
import (
|
2020-01-06 22:53:40 +08:00
|
|
|
"strings"
|
2019-11-20 13:19:46 +08:00
|
|
|
"time"
|
|
|
|
|
2019-12-22 23:15:45 +08:00
|
|
|
"github.com/hibiken/asynq/internal/base"
|
2019-12-04 13:01:26 +08:00
|
|
|
"github.com/hibiken/asynq/internal/rdb"
|
2019-12-21 23:42:32 +08:00
|
|
|
"github.com/rs/xid"
|
2019-11-20 13:19:46 +08:00
|
|
|
)
|
|
|
|
|
2019-12-07 14:00:09 +08:00
|
|
|
// A Client is responsible for scheduling tasks.
|
|
|
|
//
|
2019-12-09 22:52:43 +08:00
|
|
|
// A Client is used to register tasks that should be processed
|
2019-12-07 14:00:09 +08:00
|
|
|
// immediately or some time in the future.
|
|
|
|
//
|
|
|
|
// Clients are safe for concurrent use by multiple goroutines.
|
2019-11-20 13:19:46 +08:00
|
|
|
type Client struct {
|
2019-12-04 13:01:26 +08:00
|
|
|
rdb *rdb.RDB
|
2019-11-20 13:19:46 +08:00
|
|
|
}
|
|
|
|
|
2019-12-07 14:00:09 +08:00
|
|
|
// NewClient and returns a new Client given a redis configuration.
|
2020-01-15 13:19:06 +08:00
|
|
|
func NewClient(r RedisConnOpt) *Client {
|
|
|
|
rdb := rdb.NewRDB(createRedisClient(r))
|
2019-12-30 05:42:49 +08:00
|
|
|
return &Client{rdb}
|
2019-11-20 13:19:46 +08:00
|
|
|
}
|
|
|
|
|
2019-12-30 08:55:51 +08:00
|
|
|
// Option specifies the processing behavior for the associated task.
|
2019-12-21 23:42:32 +08:00
|
|
|
type Option interface{}
|
|
|
|
|
2020-01-06 22:53:40 +08:00
|
|
|
// Internal option representations.
|
|
|
|
type (
|
|
|
|
retryOption int
|
|
|
|
queueOption string
|
|
|
|
)
|
2019-12-21 23:42:32 +08:00
|
|
|
|
|
|
|
// MaxRetry returns an option to specify the max number of times
|
2020-01-06 23:21:14 +08:00
|
|
|
// the task will be retried.
|
2019-12-21 23:42:32 +08:00
|
|
|
//
|
|
|
|
// Negative retry count is treated as zero retry.
|
|
|
|
func MaxRetry(n int) Option {
|
|
|
|
if n < 0 {
|
|
|
|
n = 0
|
|
|
|
}
|
|
|
|
return retryOption(n)
|
|
|
|
}
|
|
|
|
|
2020-01-06 23:21:14 +08:00
|
|
|
// Queue returns an option to specify which queue to enqueue the task into.
|
2020-01-06 22:53:40 +08:00
|
|
|
//
|
|
|
|
// Queue name is case-insensitive and the lowercased version is used.
|
2020-01-06 23:21:14 +08:00
|
|
|
func Queue(name string) Option {
|
|
|
|
return queueOption(strings.ToLower(name))
|
2020-01-06 22:53:40 +08:00
|
|
|
}
|
|
|
|
|
2019-12-21 23:42:32 +08:00
|
|
|
type option struct {
|
|
|
|
retry int
|
2020-01-06 22:53:40 +08:00
|
|
|
queue string
|
2019-12-21 23:42:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func composeOptions(opts ...Option) option {
|
|
|
|
res := option{
|
|
|
|
retry: defaultMaxRetry,
|
2020-01-06 22:53:40 +08:00
|
|
|
queue: base.DefaultQueueName,
|
2019-12-21 23:42:32 +08:00
|
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
|
|
switch opt := opt.(type) {
|
|
|
|
case retryOption:
|
|
|
|
res.retry = int(opt)
|
2020-01-06 22:53:40 +08:00
|
|
|
case queueOption:
|
|
|
|
res.queue = string(opt)
|
2019-12-21 23:42:32 +08:00
|
|
|
default:
|
|
|
|
// ignore unexpected option
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Max retry count by default
|
|
|
|
defaultMaxRetry = 25
|
|
|
|
)
|
|
|
|
|
2020-01-04 12:24:18 +08:00
|
|
|
// Schedule registers a task to be processed at the specified time.
|
2019-12-07 14:00:09 +08:00
|
|
|
//
|
2020-01-04 12:24:18 +08:00
|
|
|
// Schedule returns nil if the task is registered successfully,
|
2019-12-07 14:00:09 +08:00
|
|
|
// otherwise returns non-nil error.
|
2019-12-22 02:02:03 +08:00
|
|
|
//
|
|
|
|
// opts specifies the behavior of task processing. If there are conflicting
|
|
|
|
// Option the last one overrides the ones before.
|
2020-01-04 12:24:18 +08:00
|
|
|
func (c *Client) Schedule(task *Task, processAt time.Time, opts ...Option) error {
|
2019-12-21 23:42:32 +08:00
|
|
|
opt := composeOptions(opts...)
|
2019-12-22 23:15:45 +08:00
|
|
|
msg := &base.TaskMessage{
|
2019-12-11 23:38:24 +08:00
|
|
|
ID: xid.New(),
|
2019-11-20 13:19:46 +08:00
|
|
|
Type: task.Type,
|
2020-01-05 05:13:46 +08:00
|
|
|
Payload: task.Payload.data,
|
2020-01-06 22:53:40 +08:00
|
|
|
Queue: opt.queue,
|
2019-12-21 23:42:32 +08:00
|
|
|
Retry: opt.retry,
|
2019-11-20 13:19:46 +08:00
|
|
|
}
|
2019-11-27 23:16:16 +08:00
|
|
|
return c.enqueue(msg, processAt)
|
2019-11-20 13:19:46 +08:00
|
|
|
}
|
|
|
|
|
2019-12-22 23:15:45 +08:00
|
|
|
func (c *Client) enqueue(msg *base.TaskMessage, processAt time.Time) error {
|
2019-11-27 23:16:16 +08:00
|
|
|
if time.Now().After(processAt) {
|
2019-12-04 13:01:26 +08:00
|
|
|
return c.rdb.Enqueue(msg)
|
2019-11-20 13:19:46 +08:00
|
|
|
}
|
2019-12-04 22:45:30 +08:00
|
|
|
return c.rdb.Schedule(msg, processAt)
|
2019-11-20 13:19:46 +08:00
|
|
|
}
|