Repository navigation
perf: keep api-queue-production in memory, off the disk - #1025
Merged
Merged
Conversation
api-queue-production was durable, lazy and fed persistent messages, so RabbitMQ 3.10 wrote every message to disk even though the api drains it to about zero. It is now non-durable, non-lazy and published transient. The delay queues stay durable, lazy and persistent. Must match the api's declaration of the same queue (ps2alerts/api), and the existing queue has to be deleted and redeclared once before deploy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RabbitMQ won't change an existing queue's arguments, so the durable, lazy
api-queue-productionhas to be swapped for a memory-only one once. Run this just before merging this PR and ps2alerts/api#737:--if-emptyrefuses while messages are waiting and deletes nothing. It normally sits at about 0, so re-run it a moment later./. Add-p <vhost>to both commands (and put the vhost in place of<<"/">>) if production uses another one.PRECONDITION_FAILED - inequivalent arg 'durable', so the new aggregator's API publisher can't connect inside its 5 s boot timeout, and the new api-aggregator can't consume.Rehearsed on a local
bitnamilegacy/rabbitmq:3.10.13holding the production queue arguments.--if-emptyrefused while 5 messages were waiting, the delete and redeclare left 1,000 delay messages untouched, and both new declarations were then accepted. The old api declaration was refused.What this does
api-queue-productionwas durable, lazy and fed persistent messages. RabbitMQ 3.10 therefore wrote every message to disk, even though the api drains the queue to about 0. Every delayed message was written twice: once into its delay queue, and again intoapi-queue-productionafter dead-lettering.ApiQueuenow takes adurableflag. The API queue is declared non-durable with no lazy mode, and its messages are published transient.RabbitMQ 3.10 notes:
x-queue-mode: lazywrites every message to disk, transient ones included. That is why lazy mode comes off along with durability. From 3.12 the argument is ignored and every classic queue behaves roughly lazy, so after an upgrade a non-durable queue with transient messages is the only way to keep this off the disk. Classic queues dead-letter at most once, so a dead-letter with no queue to route to is dropped.Accepted trade-off: after any RabbitMQ restart,
api-queue-productiondoesn't exist until the aggregator or api declares it again. Delay messages that expire before then are dropped. That includes every one that fell due while the broker was down. A local run on 3.10.13 confirmed that restart drops the queue and keeps the delay queues' messages.Why the delay queues come back empty after a restart
There is no code fix here. The cause is in the broker's storage or in what happens at boot, and the checks below tell which.
No code path deletes them.
destroyQueue()/deleteQueueis only reached throughQueueAuthority, which only holds the per-alertaggregator-<instance>-<event>queues.ApiQueue.destroy()has no callers. Nothing in either repo purges these queues, and every declaration of them matches.RabbitMQ keeps them. On a local
bitnamilegacy/rabbitmq:3.10.13with the production arguments, all 70,000 persistent messages in the 91 min delay queue survived three things:SIGKILL;/bitnami/rabbitmq/mnesia.Messages that expired during 30 s of downtime were dead-lettered into
api-queue-productionat boot, and none were lost.Two things do empty them:
/bitnami/rabbitmq/mnesia, and the image declares no volume. Mounted anywhere else, the data lives in the container layer. It survives a restart or a reboot, but a recreate wipes every queue: adocker compose down/up, such as the one the stack-recovery script runs. The apps then redeclare the queues empty. Reproduced locally: 5,000 messages surviveddocker restart, and the queues were gone after a recreate.ENDEDyet, or whose instance lookup fails. A Mongo error there is reported as "does not exist", which is filtered out of the logs. With this PR, those messages are dropped outright instead (see the trade-off above).Read-only checks for the box:
rabbit@localhost/msg_stores. Confirm it by checking thatcreated=matches the last stack recycle in the healthcheck log.Received Global Aggregate message for unfinished instancestraight after a restart.Validation done
yarn run lint:checkandyarn run buildpass. The aggregator has no unit test runner; jest follows in a separate PR.deliveryMode1 and delay messages persistent, and after a restart the API queue was gone while the delay queues kept their 1,001 messages.🤖 Generated with Claude Code