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

io.quarkiverse.reactive.messaging.nats.jetstream.client.ReaderSubscribtion Maven / Gradle / Ivy

There is a newer version: 3.17.0
Show newest version
package io.quarkiverse.reactive.messaging.nats.jetstream.client;

import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.microprofile.reactive.messaging.Message;
import org.jboss.logging.Logger;

import io.nats.client.JetStreamReader;
import io.nats.client.JetStreamStatusException;
import io.nats.client.JetStreamSubscription;
import io.quarkiverse.reactive.messaging.nats.jetstream.ExponentialBackoff;
import io.quarkiverse.reactive.messaging.nats.jetstream.client.configuration.ReaderConsumerConfiguration;
import io.quarkiverse.reactive.messaging.nats.jetstream.mapper.MessageMapper;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.vertx.mutiny.core.Context;

class ReaderSubscribtion

implements Subscription

{ private final static Logger logger = Logger.getLogger(ReaderSubscribtion.class); private final Connection connection; private final ReaderConsumerConfiguration

consumerConfiguration; private final JetStreamReader reader; private final JetStreamSubscription subscription; private final MessageMapper messageMapper; private final Context context; private final AtomicBoolean closed; ReaderSubscribtion(Connection connection, ReaderConsumerConfiguration

consumerConfiguration, JetStreamSubscription subscription, JetStreamReader reader, MessageMapper messageMapper, Context context) { this.connection = connection; this.consumerConfiguration = consumerConfiguration; this.subscription = subscription; this.reader = reader; this.messageMapper = messageMapper; this.context = context; this.closed = new AtomicBoolean(false); } @Override public Multi> subscribe() { boolean traceEnabled = consumerConfiguration.consumerConfiguration().traceEnabled(); Class

payloadType = consumerConfiguration.consumerConfiguration().payloadType().orElse(null); ExecutorService pullExecutor = Executors.newSingleThreadExecutor(JetstreamWorkerThread::new); return Multi.createBy().repeating() .uni(this::readNextMessage) .whilst(message -> !closed.get()) .runSubscriptionOn(pullExecutor) .emitOn(context::runOnContext) .flatMap(message -> createMulti(message.orElse(null), traceEnabled, payloadType, context)); } @Override public void onEvent(ConnectionEvent event, String message) { } @Override public void close() { this.closed.set(true); try { reader.stop(); } catch (Throwable e) { logger.warnf("Failed to stop reader with message %s", e.getMessage()); } try { if (subscription.isActive()) { subscription.drain(Duration.ofMillis(1000)); } } catch (Throwable e) { logger.warnf("Interrupted while draining subscription"); } try { if (subscription.isActive()) { subscription.unsubscribe(); } } catch (Throwable e) { logger.warnf("Failed to unsubscribe subscription with message %s", e.getMessage()); } connection.removeListener(this); } private Uni> readNextMessage() { return Uni.createFrom().emitter(emitter -> { try { if (!connection.isConnected()) { emitter.fail(new ConnectionException("The connection is not connected")); } else if (!subscription.isActive()) { emitter.fail(new ReaderException("The subscription is not active")); } else { emitter.complete(Optional .ofNullable(reader.nextMessage(consumerConfiguration.maxRequestExpires().orElse(Duration.ZERO)))); } } catch (JetStreamStatusException e) { emitter.fail(new ReaderException(e)); } catch (IllegalStateException e) { logger.warnf("The subscription became inactive for stream: %s", consumerConfiguration.consumerConfiguration().stream()); emitter.complete(Optional.empty()); } catch (InterruptedException e) { emitter.fail(new ReaderException(String.format("The reader was interrupted for stream: %s", consumerConfiguration.consumerConfiguration().stream()), e)); } catch (Throwable throwable) { emitter.fail(new ReaderException(String.format("Error reading next message from stream: %s", consumerConfiguration.consumerConfiguration().stream()), throwable)); } }); } private Multi> createMulti(io.nats.client.Message message, boolean tracingEnabled, Class

payloadType, Context context) { if (message == null || message.getData() == null) { return Multi.createFrom().empty(); } else { return Multi.createFrom() .item(() -> messageMapper.of(message, tracingEnabled, payloadType, context, new ExponentialBackoff( consumerConfiguration.consumerConfiguration().exponentialBackoff(), consumerConfiguration.consumerConfiguration().exponentialBackoffMaxDuration()), consumerConfiguration.consumerConfiguration().ackTimeout())); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy