2019-11-24 07:22:43 +08:00
|
|
|
package asynq
|
|
|
|
|
|
|
|
import (
|
2019-11-27 22:33:04 +08:00
|
|
|
"fmt"
|
2019-11-29 23:14:28 +08:00
|
|
|
"log"
|
2019-11-24 07:44:42 +08:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2019-11-24 07:22:43 +08:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Background is a top-level entity for the background-task processing.
|
|
|
|
type Background struct {
|
|
|
|
mu sync.Mutex
|
2019-11-24 12:18:39 +08:00
|
|
|
running bool
|
2019-11-24 07:22:43 +08:00
|
|
|
|
2019-11-30 12:49:18 +08:00
|
|
|
rdb *rdb
|
2019-11-24 07:22:43 +08:00
|
|
|
poller *poller
|
|
|
|
processor *processor
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBackground returns a new Background instance.
|
2019-12-04 11:43:01 +08:00
|
|
|
func NewBackground(numWorkers int, config *RedisConfig) *Background {
|
|
|
|
rdb := newRDB(config)
|
2019-11-24 07:22:43 +08:00
|
|
|
poller := newPoller(rdb, 5*time.Second, []string{scheduled, retry})
|
|
|
|
processor := newProcessor(rdb, numWorkers, nil)
|
|
|
|
return &Background{
|
2019-11-30 12:49:18 +08:00
|
|
|
rdb: rdb,
|
2019-11-24 07:22:43 +08:00
|
|
|
poller: poller,
|
|
|
|
processor: processor,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-03 12:42:21 +08:00
|
|
|
// A Handler processes a task.
|
|
|
|
//
|
|
|
|
// ProcessTask should return nil if the processing of a task
|
|
|
|
// is successful.
|
|
|
|
//
|
|
|
|
// If ProcessTask return a non-nil error or panics, the task
|
|
|
|
// will be retried after delay.
|
|
|
|
type Handler interface {
|
|
|
|
ProcessTask(*Task) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// The HandlerFunc type is an adapter to allow the use of
|
|
|
|
// ordinary functions as a Handler. If f is a function
|
|
|
|
// with the appropriate signature, HandlerFunc(f) is a
|
|
|
|
// Handler that calls f.
|
|
|
|
type HandlerFunc func(*Task) error
|
|
|
|
|
|
|
|
// ProcessTask calls fn(task)
|
|
|
|
func (fn HandlerFunc) ProcessTask(task *Task) error {
|
|
|
|
return fn(task)
|
|
|
|
}
|
2019-11-24 07:22:43 +08:00
|
|
|
|
2019-11-24 07:44:42 +08:00
|
|
|
// Run starts the background-task processing and blocks until
|
|
|
|
// an os signal to exit the program is received. Once it receives
|
|
|
|
// a signal, it gracefully shuts down all pending workers and other
|
|
|
|
// goroutines to process the tasks.
|
2019-12-03 12:42:21 +08:00
|
|
|
func (bg *Background) Run(handler Handler) {
|
2019-11-24 07:44:42 +08:00
|
|
|
bg.start(handler)
|
|
|
|
defer bg.stop()
|
|
|
|
|
|
|
|
// Wait for a signal to exit.
|
|
|
|
sigs := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(sigs, os.Interrupt, os.Kill)
|
|
|
|
<-sigs
|
2019-11-29 23:14:28 +08:00
|
|
|
fmt.Println()
|
|
|
|
log.Println("[INFO] Starting graceful shutdown...")
|
2019-11-24 07:44:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// starts the background-task processing.
|
2019-12-03 12:42:21 +08:00
|
|
|
func (bg *Background) start(handler Handler) {
|
2019-11-24 07:22:43 +08:00
|
|
|
bg.mu.Lock()
|
|
|
|
defer bg.mu.Unlock()
|
|
|
|
if bg.running {
|
|
|
|
return
|
|
|
|
}
|
2019-11-24 09:09:57 +08:00
|
|
|
|
2019-11-24 07:22:43 +08:00
|
|
|
bg.running = true
|
|
|
|
bg.processor.handler = handler
|
|
|
|
|
|
|
|
bg.poller.start()
|
|
|
|
bg.processor.start()
|
|
|
|
}
|
|
|
|
|
2019-11-24 07:44:42 +08:00
|
|
|
// stops the background-task processing.
|
|
|
|
func (bg *Background) stop() {
|
2019-11-24 07:22:43 +08:00
|
|
|
bg.mu.Lock()
|
|
|
|
defer bg.mu.Unlock()
|
|
|
|
if !bg.running {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
bg.poller.terminate()
|
|
|
|
bg.processor.terminate()
|
2019-11-24 09:09:57 +08:00
|
|
|
|
2019-11-30 12:49:18 +08:00
|
|
|
bg.rdb.client.Close()
|
2019-11-24 09:09:57 +08:00
|
|
|
bg.processor.handler = nil
|
|
|
|
bg.running = false
|
2019-11-24 07:22:43 +08:00
|
|
|
}
|