Stop Managing Job Queues: Serverless Webhook Scheduling
You need to send a webhook in 30 minutes. Maybe it’s a payment reminder. Maybe it’s a trial expiration notice. Maybe it’s a scheduled notification your user configured.
The standard playbook: spin up Redis, add a job queue library, deploy workers, monitor for stuck jobs, handle retries, pray the queue doesn’t back up during traffic spikes.
For a single delayed HTTP call.
The Infrastructure Tax
Every job queue deployment comes with operational overhead. You need to monitor queue depth. You need alerts for worker crashes. You need to handle poison messages. You need Redis persistence configured correctly or you lose jobs on restart.
Most teams underestimate this. The initial setup takes a day. The ongoing maintenance takes forever.
And the failure modes are subtle. A worker silently dies. Jobs pile up. By the time you notice, you’ve missed hundreds of webhooks and your customers are asking why their notifications never arrived.
What If Scheduling Was Just an API Call?
curl -X POST https://relay.solenoid.systems/v1/relay/schedule \
-H "Authorization: Bearer sm_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/reminder",
"method": "POST",
"body": {"user_id": "123", "type": "trial_expiring"},
"delay": "30m"
}'
That’s it. In 30 minutes, your endpoint gets hit. The response includes a webhook ID for cancellation if needed.
Delays are human-readable: "30s", "5m", "2h", "7d". No Unix timestamps, no millisecond math.
Verification Built In
Every delivery includes headers your endpoint can verify:
X-Solenoid-Signature: HMAC-SHA256 of the payloadX-Solenoid-Timestamp: When the webhook was sent
Verify authenticity in three lines:
const expected = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest('hex')
if (signature !== expected) return new Response('Invalid', { status: 401 })
No more wondering if that incoming request is legitimate or someone poking your endpoint.
Retries Without Configuration
Transient failures happen. Networks blip. Servers restart. Relay handles this automatically.
If your endpoint returns a 5xx or the connection fails, Relay retries with exponential backoff. If it returns a 4xx, Relay assumes the request is invalid and stops—no point retrying a bad payload.
You don’t configure retry counts or backoff intervals. The defaults are sane. If you need different behavior, you probably need a different tool.
The Architecture Under the Hood
Each scheduled webhook gets its own Cloudflare Durable Object. State and timer live together. When the alarm fires, the webhook delivers. On success, the object cleans up. No garbage collection jobs, no orphaned state.
This means no shared queue to bottleneck. No coordinator to fail. Each webhook is independent. Scale is horizontal by default.
When This Makes Sense
Relay is for scheduled HTTP callbacks where reliability matters more than complex routing. Good fits:
- Payment reminders and dunning emails
- Trial expiration notifications
- Scheduled user notifications
- Delayed order confirmations
- Webhook replay after maintenance windows
If you need complex job dependencies, priority queues, or rate limiting across job types, you need a real job queue. Relay is deliberately simple.
Try It
The free tier includes 10,000 calls to validate the approach. Paid tiers scale up to 2M webhooks/month on Scale ($149.99/mo).
# Schedule a test webhook to your endpoint
curl -X POST https://relay.solenoid.systems/v1/relay/schedule \
-H "Authorization: Bearer sm_your_api_key" \
-d '{"url": "https://webhook.site/your-id", "delay": "10s"}'
Ten seconds later, check webhook.site. No Redis required.