问题:
- 是否支持失败重试?
- 是否支持图形化ui?
- 是否有监控体系?
优秀版:asynq包
git地址:github.com/hibiken/asy…
- 答案1
- 是
- 答案2
- 是
- 答案3
- 是
定时任务:
client代码
package main
import (
"asynq_test/tasks"
"log"
"github.com/hibiken/asynq"
)
const redisAddr = "127.0.0.1:6379"
func main() {
// 周期性任务
scheduler := asynq.NewScheduler(
asynq.RedisClientOpt{
Addr: redisAddr,
}, nil)
task, err := tasks.NewEmailDeliveryTask(42, "some:template:id")
if err != nil {
log.Fatalf("could not create task: %v", err)
}
// 每隔1分钟同步一次
entryID, err := scheduler.Register("@every 1s", task)
if err != nil {
log.Fatal(err)
}
log.Printf("registered an entry: %q\n", entryID)
if err := scheduler.Run(); err != nil {
log.Fatal(err)
}
}
server代码:
package main
import (
"asynq_test/tasks"
"log"
"github.com/hibiken/asynq"
)
const redisAddr = "127.0.0.1:6379"
func main() {
srv := asynq.NewServer(
asynq.RedisClientOpt{Addr: redisAddr},
asynq.Config{
// Specify how many concurrent workers to use
Concurrency: 10,
// Optionally specify multiple queues with different priority.
Queues: map[string]int{
"critical": 6,
"default": 3,
"low": 1,
},
// See the godoc for other configuration options
},
)
// mux maps a type to a handler
mux := asynq.NewServeMux()
mux.HandleFunc(tasks.TypeEmailDelivery, tasks.HandleEmailDeliveryTask)
if err := srv.Run(mux); err != nil {
log.Fatalf("could not run server: %v", err)
}
}
- client端函数
- func NewScheduler(r RedisConnOpt, opts *SchedulerOpts) *Scheduler
- func NewEmailDeliveryTask(userID int, tmplID string) (*asynq.Task, error)
- func (s *Scheduler) Register(cronspec string, task *Task, opts ...Option)
- func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error)
- func (s *Scheduler) Run() error
- func (s *Scheduler) Start() error
- func (c *Cron) Start()
- func (j *enqueueJob) Run()
- func (c *Client) Enqueue(task *Task, opts ...Option) (*TaskInfo, error)
- func (c *Client) EnqueueContext(ctx context.Context, task *Task, opts ...Option) (*TaskInfo, error)
- func (c *Client) enqueue(ctx context.Context, msg *base.TaskMessage, uniqueTTL time.Duration) error
- func (r *RDB) Enqueue(ctx context.Context, msg *base.TaskMessage) error
- SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
- func (r *RDB) runScriptWithErrorCode(ctx context.Context, op errors.Op, script *redis.Script, keys []string, args ...interface{}) (int64, error)
- func (s *Scheduler) waitForSignals()
- func (s *Scheduler) Shutdown()
- func (c *Cron) Stop() context.Context
- server端函数
- func NewServer(r RedisConnOpt, cfg Config) *Server
- func NewServeMux() *ServeMux
- func (mux *ServeMux) HandleFunc(pattern string, handler func(context.Context, *Task) error)
- func (mux *ServeMux) Handle(pattern string, handler Handler)
- func (srv *Server) Run(handler Handler) error
- func (srv *Server) Start(handler Handler) error
- func (p *processor) start(wg *sync.WaitGroup)
- func (p *processor) exec()
- Dequeue(qnames ...string) (*TaskMessage, time.Time, error)
- func newTask(typename string, payload []byte, w *ResultWriter) *Task
- func (p *processor) perform(ctx context.Context, task *Task) (err error)
- func (fn HandlerFunc) ProcessTask(ctx context.Context, task *Task) error
此定时任务底层利用了cron包提供的能力
client相关的lua脚本
var enqueueCmd = redis.NewScript(`
if redis.call("EXISTS", KEYS[1]) == 1 then
return 0
end
redis.call("HSET", KEYS[1],
"msg", ARGV[1],
"state", "pending",
"pending_since", ARGV[3])
redis.call("LPUSH", KEYS[2], ARGV[2])
return 1
`)
server相关的lua脚本
keys := []string{
base.PendingKey(qname),
base.PausedKey(qname),
base.ActiveKey(qname),
base.LeaseKey(qname),
}
var dequeueCmd = redis.NewScript(`
if redis.call("EXISTS", KEYS[2]) == 0 then
local id = redis.call("RPOPLPUSH", KEYS[1], KEYS[3])
if id then
local key = ARGV[2] .. id
redis.call("HSET", key, "state", "active")
redis.call("HDEL", key, "pending_since")
redis.call("ZADD", KEYS[4], ARGV[1], id)
return redis.call("HGET", key, "msg")
end
end
return nil`)