Worker Templates
Pre-built job types available out of the box and how to implement custom handlers.
Worker templates are pre-defined job types that can be submitted directly from the dashboard's Templates page or via POST /jobs. Each template maps a Type string to a specific worker handler in worker.go.
Built-in Templates
| Template | Job Type | Key Payload Fields |
|---|---|---|
| Send Email | send_email | to, subject, body |
| WhatsApp Message | send_whatsapp | to, message |
| Webhook | webhook | url, payload |
| Generate PDF | generate_pdf | template, data |
| Image Compression | compress_image | url, width, quality |
| AI Summarizer | ai_summarize | text, length |
| M-Pesa STK Push | mpesa_stk | phone, amount, ref |
| Slack Notify | slack_notify | channel, text |
Submitting a Template Job
# Send an email
curl -X POST http://localhost:8080/jobs \
-H "X-API-Key: rtq_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"ID": "email-001",
"Type": "send_email",
"Payload": {
"to": "user@example.com",
"subject": "Welcome to Savannah Cloud",
"body": "Your account is ready."
},
"MaxRetries": 3
}'
# M-Pesa STK Push
curl -X POST http://localhost:8080/jobs \
-H "X-API-Key: rtq_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"ID": "mpesa-001",
"Type": "mpesa_stk",
"Payload": {
"phone": "254700000000",
"amount": 100,
"ref": "INV-001"
},
"MaxRetries": 2
}'Implementing Handlers
Template handlers live in worker.go inside the Process function switch statement. Add a case for each job type you want to execute:
// worker.go — inside the Process function switch
case "send_email":
to := payload["to"].(string)
subject := payload["subject"].(string)
body := payload["body"].(string)
// Call Resend / SMTP here
err = sendEmailViaResend(to, subject, body)
case "send_whatsapp":
to := payload["to"].(string)
message := payload["message"].(string)
// Call Twilio / WhatsApp Cloud API here
err = sendWhatsApp(to, message)
case "mpesa_stk":
phone := payload["phone"].(string)
amount := payload["amount"].(float64)
ref := payload["ref"].(string)
// Call Safaricom Daraja API here
err = triggerMpesaSTK(phone, int(amount), ref)
case "slack_notify":
channel := payload["channel"].(string)
text := payload["text"].(string)
err = postToSlack(channel, text)If no case matches the job type, the worker logs an unknown-type warning and marks the job as failed with 0 retries consumed.
Adding a Custom Job Type
- Choose a unique
Typestring (e.g.,resize_video) - Add a
caseinworker.go - Push jobs using that type via
POST /jobs
case "resize_video":
videoURL := payload["url"].(string)
width := int(payload["width"].(float64))
err = resizeVideo(videoURL, width)curl -X POST http://localhost:8080/jobs \
-H "X-API-Key: rtq_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"ID": "video-001",
"Type": "resize_video",
"Payload": {"url": "https://cdn.example.com/video.mp4", "width": 720},
"MaxRetries": 1
}'Retry Behaviour
MaxRetries: 0— the job runs once; failure marks itfailedimmediatelyMaxRetries: N— the job is re-enqueued up to N additional times on failure- Each attempt is logged as a separate entry in
job_logs - The current retry count is visible in the job detail view on the dashboard