问题
We are using Spring Cloud Reactive Streams with RabbitMQ.
Spring Reactive Stream appears to acknowledge the message as soon as it pulls it off the queue. So any errors unhandled exceptions that happens during the message processing need to be handled in the application (which is a different than a non-reactive stream where unhandled exceptions can be thrown and a message would be rejected, thus sending it to a dead letter queue).
How are we supposed to deal with a sudden shutdown in an application when a message is in flight?
For instance:
- Application pulls message off of queue
- Application marks message as acknowledged
- Application starts message processing
- Application is shut down before message processing is complete
When this happens, the message appears to be lost completely, since it is off of the queue but the application is stopped. How can we recover these messages?
回答1:
You need to use manual acknowledgments and defer the acks until processing is asynchronously completed. To do that, you need to consume the whole message:
@Bean
public Consumer<Flux<Message<String>>> async() {
return inbound -> inbound
...
.map(msg -> {
try {
msg.getHeaders().get(AmqpHeaders.CHANNEL, Channel.class)
.basicAck(msg.getHeaders().get(AmqpHeaders.DELIVERY_TAG, Long.class), false);
}
catch (IOException e) {
e.printStackTrace();
}
return msg.getPayload();
})
.subscribe(System.out::println);
}
spring:
cloud:
stream:
function.definition: async
bindings:
async-in-0:
destination: testtock
group: async
rabbit:
bindings:
async-in-0:
consumer:
acknowledge-mode: MANUAL
prefetch: 10
Use basicReject
to requeue or send to the DLQ.
来源:https://stackoverflow.com/questions/61126117/spring-reactive-stream-unexpected-shutdown