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

com.codeheadsystems.queue.impl.MessageConsumerExecutor Maven / Gradle / Ivy

The newest version!
package com.codeheadsystems.queue.impl;

import static com.codeheadsystems.queue.module.QueueModule.QUEUE_PROCESSOR_EXECUTOR;

import com.codeheadsystems.metrics.Metrics;
import com.codeheadsystems.metrics.Tags;
import io.dropwizard.lifecycle.Managed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.codeheadsystems.queue.Message;
import com.codeheadsystems.queue.MessageConsumer;
import com.codeheadsystems.queue.State;
import com.codeheadsystems.queue.dao.MessageDao;

/**
 * The type Message consumer executor.
 */
@Singleton
public class MessageConsumerExecutor implements Managed {
  private static final Logger LOGGER = LoggerFactory.getLogger(MessageConsumerExecutor.class);

  private final ExecutorService executorService;
  private final MessageDao messageDao;
  private final QueueRegister queueRegister;
  private final Metrics metrics;

  /**
   * Instantiates a new Message consumer executor.
   *
   * @param executorService the executor service
   * @param messageDao      the message dao
   * @param queueRegister   the queue register
   * @param metrics         the metrics
   */
  @Inject
  public MessageConsumerExecutor(@Named(QUEUE_PROCESSOR_EXECUTOR) final ExecutorService executorService,
                                 final MessageDao messageDao,
                                 final QueueRegister queueRegister,
                                 final Metrics metrics) {
    this.executorService = executorService;
    this.messageDao = messageDao;
    this.queueRegister = queueRegister;
    this.metrics = metrics;
    LOGGER.info("MessageConsumerExecutor({},{},{})", messageDao, executorService, queueRegister);
  }

  /**
   * Enqueue.
   *
   * @param message the message
   */
  public void enqueue(final Message message) {
    LOGGER.trace("enqueue({})", message);
    final String messageType = message.messageType();
    metrics.time("MessageConsumerExecutor.enqueue", Tags.of("messageType", messageType), () -> {
      queueRegister.getConsumer(messageType)
          .ifPresentOrElse(
              messageConsumer -> executorService.execute(() -> execute(message, messageConsumer)),
              () -> {
                LOGGER.error("No message for type {}", message.messageType());
                messageDao.delete(message);
              });
      return null;
    });
  }

  private void execute(final Message message, final MessageConsumer consumer) {
    LOGGER.trace("execute({},{})", message, consumer);
    try {
      metrics.time("MessageConsumerExecutor.execute", Tags.of("messageType", message.messageType()), () -> {
        messageDao.updateState(message, State.PROCESSING);
        consumer.accept(message);
        return null;
      });
    } catch (final Throwable t) {
      // TODO: There is no dead letter queue... yet
      LOGGER.error("Error processing message: {}", message, t); // do not die
    } finally {
      messageDao.delete(message);
    }
  }

  @Override
  public void start() throws Exception {
    LOGGER.info("Executor service enabled to start executing messages");
  }

  @Override
  public void stop() throws Exception {
    LOGGER.info("stop()");
    LOGGER.info("Shutting down the executor service");
    executorService.shutdown();
    if (!executorService.awaitTermination(15, TimeUnit.SECONDS)) {
      LOGGER.info("Shutting down nicely failed. No longer being nice.");
      executorService.shutdownNow().forEach(runnable -> LOGGER.warn("Unable to shutdown {}", runnable));
    }
    LOGGER.info("Executor service no longer executing messages");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy