Add the rabbitmq module
This commit is contained in:
82
rabbitmq/docs/05-acknowledgement.md
Normal file
82
rabbitmq/docs/05-acknowledgement.md
Normal file
@@ -0,0 +1,82 @@
|
||||
[← Dead-lettering](04-dead-lettering.md) · [Module README](../README.md) · [Changing your mind →](06-changing-your-mind.md)
|
||||
|
||||
# 5. Acknowledgement
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
rabbitmq:
|
||||
listener:
|
||||
simple:
|
||||
acknowledge-mode: manual
|
||||
prefetch: 1
|
||||
```
|
||||
|
||||
Three modes, and the default is not the one you want for work that matters.
|
||||
|
||||
| Mode | Behaviour |
|
||||
|---|---|
|
||||
| `auto` (default) | the container acks after the listener returns, nacks on exception |
|
||||
| `manual` | your code calls `basicAck` / `basicNack`; nothing else does |
|
||||
| `none` | the broker forgets the message the moment it is delivered |
|
||||
|
||||
(Boot publishes no default for `acknowledge-mode` either; the field initialiser in
|
||||
`AbstractMessageListenerContainer` is `AcknowledgeMode.AUTO`.)
|
||||
|
||||
`none` is genuinely fire-and-forget: no redelivery, ever, and no flow control either, because
|
||||
`prefetch` is meaningless without acknowledgement. It is the right choice for metrics and the
|
||||
wrong choice for everything else.
|
||||
|
||||
`auto` is a reasonable default and its name is misleading: it does not mean "auto-ack" in the
|
||||
AMQP sense (that is `none`). It means the container decides, and it decides by whether your
|
||||
listener threw.
|
||||
|
||||
`manual` is what you want when the acknowledgement must happen after some other durable side
|
||||
effect — a database commit, a downstream call. In `manual` mode the listener takes a `Channel`
|
||||
and a delivery tag:
|
||||
|
||||
```java
|
||||
@RabbitListener(queues = "orders.work")
|
||||
void onOrder(OrderMessage message, Channel channel,
|
||||
@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
|
||||
try {
|
||||
process(message);
|
||||
channel.basicAck(tag, false);
|
||||
}
|
||||
catch (TransientFailure ex) {
|
||||
channel.basicNack(tag, false, !alreadyRedelivered);
|
||||
}
|
||||
catch (PermanentFailure ex) {
|
||||
channel.basicNack(tag, false, false); // dead-letter it
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The two catch blocks are the point. A single `catch (Exception)` that nacks with `requeue=true`
|
||||
is the loop from [chapter 4](04-dead-lettering.md); a single one that nacks with `requeue=false`
|
||||
dead-letters transient failures that would have succeeded on a retry. Deciding which kind of
|
||||
failure you had is work you cannot delegate to the container.
|
||||
|
||||
## `prefetch` is the flow-control knob
|
||||
|
||||
`prefetch` is how many un-acknowledged messages the broker will send a consumer. Spring Boot sets
|
||||
no default, so `AbstractMessageListenerContainer.DEFAULT_PREFETCH_COUNT` applies, and that
|
||||
constant is **250** — throughput-oriented: a slow consumer holds 250 messages that no
|
||||
other consumer can take, so one stuck worker parks 250 messages behind it.
|
||||
|
||||
Set it to 1 when messages are expensive and unevenly sized — it gives you round-robin
|
||||
distribution across consumers. Leave it high when messages are small and uniform and you want
|
||||
throughput. This is the single most effective RabbitMQ tuning parameter and it is almost never
|
||||
touched.
|
||||
|
||||
## The forgotten ack
|
||||
|
||||
Not calling `basicAck` does not lose the message and does not throw. The message stays
|
||||
un-acknowledged, counting against `prefetch`, until the channel closes. With `prefetch: 1` the
|
||||
consumer stops after exactly one message; with the default it stops after 250. Both look like the
|
||||
consumer "just stopped", hours apart in wall-clock time depending on traffic.
|
||||
|
||||
`rabbitmqctl list_queues name messages_ready messages_unacknowledged` is the command that
|
||||
distinguishes them. A large `messages_unacknowledged` with a live consumer means somebody forgot
|
||||
an ack.
|
||||
|
||||
[Changing your mind →](06-changing-your-mind.md)
|
||||
Reference in New Issue
Block a user