All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.reactivecommons.async.rabbit.RabbitDirectAsyncGateway Maven / Gradle / Ivy

The newest version!
package org.reactivecommons.async.rabbit;

import io.cloudevents.CloudEvent;
import io.micrometer.core.instrument.MeterRegistry;
import org.reactivecommons.api.domain.Command;
import org.reactivecommons.async.api.AsyncQuery;
import org.reactivecommons.async.api.DirectAsyncGateway;
import org.reactivecommons.async.api.From;
import org.reactivecommons.async.commons.config.BrokerConfig;
import org.reactivecommons.async.commons.converters.MessageConverter;
import org.reactivecommons.async.commons.reply.ReactiveReplyRouter;
import org.reactivecommons.async.rabbit.communications.ReactiveMessageSender;
import reactor.core.observability.micrometer.Micrometer;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.rabbitmq.OutboundMessageResult;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;

import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;

import static java.lang.Boolean.TRUE;
import static org.reactivecommons.async.api.HandlerRegistry.DEFAULT_DOMAIN;
import static org.reactivecommons.async.commons.Headers.COMPLETION_ONLY_SIGNAL;
import static org.reactivecommons.async.commons.Headers.CORRELATION_ID;
import static org.reactivecommons.async.commons.Headers.REPLY_ID;
import static org.reactivecommons.async.commons.Headers.REPLY_TIMEOUT_MILLIS;
import static org.reactivecommons.async.commons.Headers.SERVED_QUERY_ID;

public class RabbitDirectAsyncGateway implements DirectAsyncGateway {

    private final BrokerConfig config;
    private final ReactiveReplyRouter router;
    private final ReactiveMessageSender sender;
    private final String exchange;
    private final MessageConverter converter;
    private final boolean persistentCommands;
    private final boolean persistentQueries;
    private final Duration replyTimeout;
    private final MeterRegistry meterRegistry;


    public RabbitDirectAsyncGateway(BrokerConfig config, ReactiveReplyRouter router, ReactiveMessageSender sender,
                                    String exchange, MessageConverter converter, MeterRegistry meterRegistry) {
        this.config = config;
        this.router = router;
        this.sender = sender;
        this.exchange = exchange;
        this.converter = converter;
        this.persistentCommands = config.isPersistentCommands();
        this.persistentQueries = config.isPersistentQueries();
        this.replyTimeout = config.getReplyTimeout();
        this.meterRegistry = meterRegistry;
    }

    @Override
    public  Mono sendCommand(Command command, String targetName) {
        return sendCommand(command, targetName, 0, DEFAULT_DOMAIN);
    }

    @Override
    public  Mono sendCommand(Command command, String targetName, long delayMillis) {
        return sendCommand(command, targetName, delayMillis, DEFAULT_DOMAIN);
    }

    @Override
    public  Mono sendCommand(Command command, String targetName, String domain) {
        return sendCommand(command, targetName, 0, domain);
    }

    @Override
    public  Mono sendCommand(Command command, String targetName, long delayMillis, String domain) {
        Tuple2> targetAndHeaders = validateDelay(targetName, delayMillis);
        return resolveSender(domain).sendWithConfirm(command, exchange, targetAndHeaders.getT1(),
                targetAndHeaders.getT2(), persistentCommands);
    }

    @Override
    public Mono sendCommand(CloudEvent command, String targetName) {
        return sendCommand(command, targetName, 0, DEFAULT_DOMAIN);
    }

    @Override
    public Mono sendCommand(CloudEvent command, String targetName, long delayMillis) {
        return sendCommand(command, targetName, delayMillis, DEFAULT_DOMAIN);
    }

    @Override
    public Mono sendCommand(CloudEvent command, String targetName, String domain) {
        return sendCommand(command, targetName, 0, domain);
    }

    @Override
    public Mono sendCommand(CloudEvent command, String targetName, long delayMillis, String domain) {
        Tuple2> targetAndHeaders = validateDelay(targetName, delayMillis);
        return resolveSender(domain).sendWithConfirm(command, exchange, targetAndHeaders.getT1(),
                targetAndHeaders.getT2(), persistentCommands);
    }

    public  Flux sendCommands(Flux> commands, String targetName) {
        return sender.sendWithConfirmBatch(commands, exchange, targetName, Collections.emptyMap(), persistentCommands);
    }


    @Override
    public  Mono requestReply(AsyncQuery query, String targetName, Class type) {
        return requestReply(query, targetName, type, DEFAULT_DOMAIN);
    }

    @Override
    public  Mono requestReply(AsyncQuery query, String targetName, Class type, String domain) {
        return requestReplyInternal(query, targetName, type, domain, AsyncQuery::getResource);
    }

    @Override
    public  Mono requestReply(CloudEvent query, String targetName, Class type) {
        return requestReplyInternal(query, targetName, type, DEFAULT_DOMAIN, CloudEvent::getType);
    }

    @Override
    public  Mono requestReply(CloudEvent query, String targetName, Class type, String domain) {
        return requestReplyInternal(query, targetName, type, domain, CloudEvent::getType);
    }

    private  Mono requestReplyInternal(T query, String targetName, Class type, String domain, Function queryTypeExtractor) {
        final String correlationID = UUID.randomUUID().toString().replaceAll("-", "");

        final Mono replyHolder = router.register(correlationID)
                .timeout(replyTimeout)
                .doOnError(TimeoutException.class, e -> router.deregister(correlationID))
                .map(s -> converter.readValue(s, type));

        Map headers = new HashMap<>();
        headers.put(REPLY_ID, config.getRoutingKey());
        headers.put(SERVED_QUERY_ID, queryTypeExtractor.apply(query));
        headers.put(CORRELATION_ID, correlationID);
        headers.put(REPLY_TIMEOUT_MILLIS, replyTimeout.toMillis());

        return resolveSender(domain).sendNoConfirm(query, exchange, targetName + ".query", headers, persistentQueries)
                .then(replyHolder)
                .name("async_query")
                .tag("operation", queryTypeExtractor.apply(query))
                .tag("target", targetName)
                .tap(Micrometer.metrics(meterRegistry));
    }

    @Override
    public  Mono reply(T response, From from) {
        final HashMap headers = new HashMap<>();
        headers.put(CORRELATION_ID, from.getCorrelationID());

        if (response == null) {
            headers.put(COMPLETION_ONLY_SIGNAL, TRUE.toString());
        }

        return sender.sendNoConfirm(response, "globalReply", from.getReplyID(), headers, false);
    }

    protected ReactiveMessageSender resolveSender(String domain) { // NOSONAR
        return sender;
    }

    private Tuple2> validateDelay(String targetName, long delayMillis) {
        Map headers = new HashMap<>();
        String realTarget = targetName;
        if (delayMillis > 0) {
            headers.put(DELAYED, String.valueOf(delayMillis));
            realTarget = targetName + "-delayed";
        }
        return Tuples.of(realTarget, headers);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy