簡體   English   中英

RabbitMQ + Reactor,傳遞消息后發送ACK?

[英]RabbitMQ + Reactor, sending ACK after passing on message?

我試圖弄清楚Project-Reactor是否適用於我的用例。

我需要在我的應用程序中保持高度一致性,我想:

  1. 收到RabbitMQ發來的消息
  2. 做一些操縱/轉換
  3. 將消息放在(不同的)RabbitMQ隊列上
  4. 發送原始消息的ACK

使用普通的RabbitMQ Java庫,它大致如下所示:

var connectionFactory = new ConnectionFactory();
var connection = connectionFactory.newConnection();
var channel = connection.createChannel();
channel.txSelect();
channel.queueDeclare("queue.A", true, false, false, null);
channel.queueDeclare("queue.B", true, false, false, null);

channel.basicConsume("queue.A", false, (tag, delivery) ->
{
    String data = new String(delivery.getBody(), StandardCharsets.UTF_8);
    System.out.println("Received: " + data);
    channel.basicPublish("", "queue.B", null, data.getBytes(StandardCharsets.UTF_8));
    channel.txCommit();
    System.out.println("Sending ACK");
    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
    channel.txCommit();

}, tag -> System.err.println("Tag " + tag + " failed"));

這很好地打印

Received: DATA
Sending ACK

使用Reactor-RabbitMQ我想出了以下內容:

var options = new ReceiverOptions();
var receiver = RabbitFlux.createReceiver(options);
var sender = RabbitFlux.createSender();
sender.declare(QueueSpecification.queue("queue.A")).block();
sender.declare(QueueSpecification.queue("queue.B")).block();
sender
    .send(receiver.consumeManualAck("queue.A")
        .doOnError(ex -> ex.printStackTrace())
        .doOnEach(s ->
        {
            s.get().ack();
            print("ACK");
        })
        .map(ad ->
        {
            print("MAP");
            return new OutboundMessage("", "queue.B", ad.getBody());
        }))
    .doOnEach(v ->
    {
        print("SUB");
    })
    .subscribe();

但是,這打印

ACK
MAP

這是不正確的順序,很明顯的,因為我做的doOnEach之前map 但是,在我將發送者映射到OutboundMessage之后, AcknowledgableDelivery不再可用。

請注意,從不打印SUB 可能是因為send訂閱是連續的,並且永遠不會達到Mono<Void>終止狀態。

我對Reactor的了解並不那么廣泛,所以我覺得我錯過了一些我可以在這里使用的東西。 有可能用Reactor做得很整齊,還是應該忘掉它?


腳注:我正在使用var因為我在Java 11中,而print語句是一種量化事物執行順序的方法。

我不認為可以確認內部發送方法。 相反,你可以嘗試:

receiver.consumeManualAck("queue.A")
        .flatMap(ad -> {
           Mono<OutboundMessage> outboundMessageMono =
                Mono.just(new OutboundMessage("", "queue.B", ad.getBody()));
           return sender.send(outboundMessageMono)
                        .doFinally(signalType -> {
                            if (signalType == SignalType.ON_COMPLETE) {
                               ad.ack();
                            } else {
                               ad.nack(false);
                           }
                         });
         });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM