Webhook Follow-Up Task Scheduling: One Hour Later with Queues or Cron Explained
Webhook Follow-Up Scheduling: Delayed Messages vs Per-Event Timers Explained Short answer: for a logistics webhook that must run about an hour later, put a durable due time in a queue-backed table and let a bounded worker claim it; use a cron sweep as the recovery path, not one timer per event. This keeps latency visible while a rate-limited pool drains at a controlled cost. Imagine a carrier…
When scheduling a webhook follow-up task to run approximately one hour later, using a durable delayed queue or per-event cron entry are two common approaches. However, each has its own set of advantages and drawbacks.
For a logistics webhook requiring an hourly delay, it is recommended to store the event ID, action, intended run time, attempt count, and a deduplication key in a single transaction alongside the business update. This ensures the follow-up task is recorded in a durable state. The webhook can then return a success response to the carrier without performing the slow follow-up immediately.
To implement this, create a `FollowUp` table with fields for event ID, kind, runAt timestamp, attempts, and dedupeKey. A poller can then claim ready rows using short batches, leveraging PostgreSQL's `FOR UPDATE SKIP LOCKED` to prevent concurrent workers from claiming the same row. The actual task should be executed outside the database transaction to avoid blocking the transaction.
Implement a claimReady function to retrieve ready rows based on the desired batch size. This function should consider factors such as queue age, claim duration, downstream response time, retry count, and the number of ready rows. Logging should include the webhook ID and dedupe key to trace a delivery across retries.
When comparing delayed message queues and cron sweeps, delayed queues offer convenience through built-in retry and visibility settings managed by the broker. However, they also introduce operational dependencies such as retention and ordering rules. In contrast, a cron sweep over a due-time table provides greater inspectability, allowing operators to query late rows, replay events, or change leases without relying on broker-specific consoles. The trade-off is the added latency from polling.
Per-event timers are the simplest to code but lack durability, making them suitable only for single-process utilities where missing a follow-up is not critical. They are not ideal for scenarios requiring auditability, frequent deployments, or multiple replicas receiving the same webhook.
To handle failures gracefully, treat the worker as a control loop that discovers ready work, admits it based on the downstream limit, executes it idempotently, and records the next state. Implement a semaphore around the carrier call to control concurrency. A drain loop can manage the worker, releasing permits as calls complete and leaving remaining rows in the ready state.
Monitor metrics such as age at execution, queue age, retry counts, and retries-to-completions ratio to ensure the system is running smoothly and to prevent overload scenarios.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.