Repository navigation
fix: delay queues are never redeclared - #39
Conversation
|
Thanks for the report and the patch — the diagnosis is correct, and it is a regression I introduced in #38. Before that, The approach is right, and keying on One thing needs tightening before this can go in. The window is derived from
Two consequences: 1. Carbon::setTestNow('2026-08-18 09:40:57.000');
$this->bindConfig(['delay_queue_granularity' => 300]);
// ...
$queue->laterRaw(1, '{"id":"a"}', 'orders'); // ttl 1200 ms, x-expires 2400 ms
Carbon::setTestNow('2026-08-18 09:40:58.500'); // past x-expires - ttl
$queue->laterRaw(1, '{"id":"b"}', 'orders');
$this->assertSame(2, $this->countDeclarations($declaredNames, 'orders.delay.1200'));
// Failed asserting that 1 is identical to 2That is the original bug again, in a smaller window. 2. In the default config the margin is resolution-limited rather than merely small. Both go away with Two smaller things:
With the window tightened I will merge this and cut a release. |
Summary
Delayed jobs are held in a
<queue>.delay.<ttl>queue that RabbitMQ deletes once it falls idle (x-expires), but$declaredTopologymemoizes the declaration for the life of the process with no invalidation.A publisher whose last publish to that TTL bucket was longer ago than the queue's lifetime therefore skips the redeclare and publishes into a queue that no longer exists — the default exchange discards the message silently, with no exception and no failed job.
Any workload that dispatches delayed jobs at intervals hits this routinely: with several worker processes each keeping its own memo, one process's gap between publishes to the same bucket easily exceeds
x-expires, and the job is lost.Type of change
Checklist
CONTRIBUTING.md.composer format-testpasses.composer analysepasses.composer testpasses.Runtime matrix checked
Notes for reviewers