To use Asynq, you must define two things: how to create a task and how to process it.
1. Task Creation
A task consists of a type (a string) and a payload (byte slice). It is best practice to wrap task creation in a helper function that marshals your data into JSON.
2. Task Handling
Handlers process the tasks. You can implement them in two ways:
asynq.HandlerFunc: A simple function with the signature func(context.Context, *asynq.Task) error.asynq.Handler interface: A struct that implements the ProcessTask(context.Context, *asynq.Task) error method. This is useful when your handler needs to maintain state or dependencies.
// Task definition example
const TypeEmailDelivery = "email:deliver"
type EmailDeliveryPayload struct {
UserID int
TemplateID string
}
func NewEmailDeliveryTask(userID int, tmplID string) (*asynq.Task, error) {
payload, err := json.Marshal(EmailDeliveryPayload{UserID: userID, TemplateID: tmplID})
if err != nil {
return nil, err
}
return asynq.NewTask(TypeEmailDelivery, payload), nil
}
// HandlerFunc example
func HandleEmailDeliveryTask(ctx context.Context, t *asynq.Task) error {
var p EmailDeliveryPayload
if err := json.Unmarshal(t.Payload(), &p); err != nil {
return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
}
// ... logic
return nil
}
// Handler interface example
type ImageProcessor struct {}
func (processor *ImageProcessor) ProcessTask(ctx context.Context, t *asynq.Task) error {
// ... logic
return nil
}