RabbitMQ + Reactor, el envío de ACK después de pasar el mensaje?

Gelunox:

Estoy tratando de averiguar si el proyecto-Reactor es una opción viable para mi caso de uso.

Necesito una alta consistencia en mi solicitud, yo quiero:

  1. Recibe un mensaje de RabbitMQ
  2. Haga un poco de manipulación / transformación
  3. Poner el mensaje en un (diferente) cola RabbitMQ
  4. Enviar un ACK para el mensaje original

Con la biblioteca de Java normales RabbitMQ sería más o menos algo parecido a esto:

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"));

Esto imprime muy bien

Received: DATA
Sending ACK

Usando Reactor-RabbitMQ Yo he llegado con la siguiente:

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();

Sin embargo, esto impresiones

ACK
MAP

Que no es el orden correcto, obviamente, porque estoy haciendo el doOnEachantes map. Pero el AcknowledgableDeliveryya no está disponible después de que ha trazado para OutboundMessageel remitente.

Tenga en cuenta que SUBno se imprime. Probablemente porque la sendsuscripción es continua y nunca alcanza el Mono<Void>estado terminado.

Mi conocimiento del reactor no es tan extensa, por lo que siento que me falta algo que podría utilizar aquí. ¿Es posible hacer esto perfectamente con Reactor o debería olvidarse de él?


Nota al pie: estoy usando varporque estoy en Java 11, y las declaraciones de impresión como una manera de cuantificar el orden en que se ejecutan las cosas.

pmackowski:

Creo que no es posible reconocer método de envío dentro. En su lugar puede probar:

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);
                           }
                         });
         });

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=219850&siteId=1
Recomendado
Clasificación