59 lines
2.5 KiB
Markdown
59 lines
2.5 KiB
Markdown
[← Acknowledgement](05-acknowledgement.md) · [Module README](../README.md)
|
|
|
|
# 6. Changing your mind about a queue
|
|
|
|
Queue arguments are immutable. There is no `ALTER QUEUE`. Redeclaring an existing queue with
|
|
different arguments is a channel-level error
|
|
([`docs/output/precondition-failed.txt`](output/precondition-failed.txt)):
|
|
|
|
```
|
|
PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue 'orders.ttl' in vhost '/':
|
|
received '9999' but current is '1500', class-id=50, method-id=10
|
|
```
|
|
|
|
Reply code **406**. The message is precise and helpful, and you will probably never see it,
|
|
because of what Spring wraps it in:
|
|
|
|
```
|
|
AmqpIOException: java.io.IOException
|
|
caused by: null
|
|
caused by: channel error; protocol method: #method<channel.close>(reply-code=406, ...)
|
|
```
|
|
|
|
`AmqpIOException`'s own message is the string `java.io.IOException`. The next cause's message is
|
|
`null`. The useful text is two levels down. This is why the failure gets reported as "some
|
|
IOException from RabbitMQ" and why it is worth writing a log statement that walks the cause
|
|
chain.
|
|
|
|
## What this means operationally
|
|
|
|
Changing a TTL, a max-length, a dead-letter exchange or a queue type on a live queue is not a
|
|
config edit. It is a migration:
|
|
|
|
1. declare the new queue under a new name
|
|
2. bind it alongside the old one
|
|
3. move consumers over
|
|
4. drain the old queue
|
|
5. delete it
|
|
|
|
Plan the rename into the change from the start — `orders.work.v2` is not ugly, it is honest.
|
|
|
|
## Related failure modes
|
|
|
|
**A failed declaration stops the ones after it.** `RabbitAdmin` declares beans on connection, and
|
|
a `PRECONDITION_FAILED` closes the channel. Declarations queued behind it on that channel do not
|
|
happen. So one stale queue argument can leave half your topology undeclared, and the symptom is a
|
|
*different* queue being missing.
|
|
|
|
**Declarations happen on connection, not on context refresh.** A broken topology does not fail
|
|
startup; it fails the first publish. If you want it to fail at boot, force a connection early —
|
|
`connectionFactory.createConnection()` in an `ApplicationRunner` is enough.
|
|
|
|
**`missing-queues-fatal` defaults differently for the two container types.** It is `true` for
|
|
`spring.rabbitmq.listener.simple` and `false` for `spring.rabbitmq.listener.direct`. So the same
|
|
missing queue kills a simple container and is quietly tolerated by a direct one, which makes
|
|
"it works in that service" an unhelpful data point. Combined with the point above, a topology
|
|
error can present as a listener startup problem in one service and as silence in another.
|
|
|
|
[Module README](../README.md)
|