Short answer: use a Node.js cron setup that claims due database cleanup rows with a lease; use a durable queue only when retry backlog and replay controls justify the extra state machine.
A cleanup job in a logistics backend should be boring: claim old rows, make one bounded attempt, record the result, and leave the next run enough information to recover. For outbound shipment webhooks, that means a retry must never turn one delivery into two customer-visible state changes.
The least complex setup is a single Node.js worker process triggered by a scheduler, with the database as the source of truth for claims and idempotency. A cron expression alone cannot provide delivery semantics. It only provides a chance to run code.
That is the boundary.…