Skip to main content

Overview

Argos Mesh uses RabbitMQ as the message broker for asynchronous communication between microservices. The system implements a topic-based exchange pattern for flexible routing of events.

Connection Configuration

Basic Connection Settings

spring.rabbitmq.host
string
required
RabbitMQ server hostnameDefault: message_broker (Docker service name)Production: Use FQDN or IP address
spring.rabbitmq.port
number
required
AMQP protocol portDefault: 5672
spring.rabbitmq.username
string
required
Authentication usernameDefault: admin
spring.rabbitmq.password
string
required
Authentication passwordDefault: admin123
Change default credentials in production!
spring.rabbitmq.listener.simple.prefetch
number
Number of messages to prefetch per consumerDefault: 1Purpose: Fair dispatch - each consumer processes one message at a time

Application Properties Example

spring.rabbitmq.host=message_broker
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin123
spring.rabbitmq.listener.simple.prefetch=1

Queue and Exchange Architecture

Orders Service Queues

The Orders service publishes events related to sales and product management.
argos.sales.queue
Queue
Queue Name: argos.sales.queueDurability: true (survives broker restart)Purpose: Receives sales transaction eventsExchange: shop.exchangeRouting Key: shop.event.sold
argos.products.mgmt.queue
Queue
Queue Name: argos.products.mgmt.queueDurability: truePurpose: Receives product lifecycle events (created, updated, deleted)Exchange: shop.exchangeRouting Key: shop.event.product.# (wildcard)

Configuration Code

orders/config/RabbitMQConfig.java
@Configuration
public class RabbitMQConfig {

    public static final String QUEUE_SALE = "argos.sales.queue";
    public static final String QUEUE_PRODUCTS = "argos.products.mgmt.queue";
    
    public static final String EXCHANGE_NAME = "shop.exchange";
    public static final String RK_SALES = "shop.event.sold";
    public static final String RK_PRODUCTS = "shop.event.product.#";

    @Bean
    public Queue salesQueue() {
        return new Queue(QUEUE_SALE, true);
    }

    @Bean
    public Queue productsQueue() {
        return new Queue(QUEUE_PRODUCTS, true);
    }

    @Bean
    public TopicExchange exchange() {
        return new TopicExchange(EXCHANGE_NAME);
    }

    @Bean
    public Binding bindingSales(Queue salesQueue, TopicExchange exchange) {
        return BindingBuilder.bind(salesQueue).to(exchange).with(RK_SALES);
    }

    @Bean
    public Binding bindingProducts(Queue productsQueue, TopicExchange exchange) {
        return BindingBuilder.bind(productsQueue).to(exchange).with(RK_PRODUCTS);
    }
}

Sentinel Service Queues

The Sentinel service consumes events for monitoring and alert generation.
argos.sales.queue
Queue
Queue Name: argos.sales.queueDurability: truePurpose: Monitors sales for rate limiting analysisExchange: shop.exchangeRouting Key: shop.event.sold
argos.alert.queue
Queue
Queue Name: argos.alert.queueDurability: truePurpose: Publishes security alerts when suspicious activity is detectedExchange: alert.exchangeRouting Key: argos.alert.# (wildcard)

Configuration Code

sentinel/config/RabbitMQConfig.java
@Configuration
public class RabbitMQConfig {
    public static final String QUEUE_ALERT = "argos.alert.queue";
    public static final String ALERT_EXCHANGE = "alert.exchange";
    public static final String RK_ALERT = "argos.alert.#";

    public static final String QUEUE_SALE = "argos.sales.queue";    
    public static final String EXCHANGE_SOLD = "shop.exchange";
    public static final String RK_SALES = "shop.event.sold";

    // Notifications queue
    @Bean
    public Queue alertQueue() {
        return new Queue(QUEUE_ALERT, true);
    }

    @Bean
    public TopicExchange exchange() {
        return new TopicExchange(ALERT_EXCHANGE);
    }

    @Bean
    public Binding binding(Queue alertQueue, TopicExchange exchange) {
        return BindingBuilder.bind(alertQueue).to(exchange).with(RK_ALERT);
    }

    // Sales queue
    @Bean
    public Queue salesQueue() {
        return new Queue(QUEUE_SALE, true);
    }

    @Bean
    public TopicExchange exchangeSold() {
        return new TopicExchange(EXCHANGE_SOLD);
    }

    @Bean
    public Binding bindingSales(Queue salesQueue, TopicExchange exchange) {
        return BindingBuilder.bind(salesQueue).to(exchange).with(RK_SALES);
    }
}

Notify Service Queues

The Notify service consumes alert events for notification delivery.
argos.alert.queue
Queue
Queue Name: argos.alert.queueDurability: truePurpose: Consumes alerts and sends notificationsExchange: alert.exchangeRouting Key: argos.alert.# (wildcard)

Configuration Code

notify/config/RabbitMQConfig.java
@Configuration
public class RabbitMQConfig {

    public static final String QUEUE_ALERT = "argos.alert.queue";
    public static final String ALERT_EXCHANGE = "alert.exchange";
    public static final String RK_ALERT = "argos.alert.#";

    @Bean
    public Queue alertQueue() {
        return new Queue(QUEUE_ALERT, true);
    }

    @Bean
    public TopicExchange exchange() {
        return new TopicExchange(ALERT_EXCHANGE);
    }

    @Bean
    public Binding binding(Queue alertQueue, TopicExchange exchange) {
        return BindingBuilder.bind(alertQueue).to(exchange).with(RK_ALERT);
    }
}

Message Serialization

All services use Jackson JSON for message serialization with custom configuration:
RabbitMQConfig.java
@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    return mapper;
}

@Bean
public MessageConverter jsonMessageConverter(ObjectMapper objectMapper) {
    return new Jackson2JsonMessageConverter(objectMapper);
}
The JavaTimeModule enables proper serialization of Java 8+ date/time types (LocalDateTime, Instant, etc.) without timestamps.

Routing Patterns

Topic Exchange Routing

Argos Mesh uses Topic Exchanges for flexible message routing:
Routing KeyPatternQueuePurpose
shop.event.soldExact matchargos.sales.queueSales transactions
shop.event.product.#Wildcardargos.products.mgmt.queueProduct events
argos.alert.#Wildcardargos.alert.queueSecurity alerts
Hash (#) Wildcard: Matches zero or more wordsExamples:
  • shop.event.product.# matches:
    • shop.event.product.created
    • shop.event.product.updated
    • shop.event.product.deleted
Star (*) Wildcard: Matches exactly one wordExample:
  • shop.event.* matches:
    • shop.event.sold
    • shop.event.created
  • But NOT shop.event.product.created
All queues are marked as durable (true), which means:
  • Queues survive RabbitMQ broker restarts
  • Messages are not lost on broker failure (when marked as persistent)
  • Suitable for production environments
Non-durable queues are deleted when the broker restarts.
Setting prefetch=1 ensures fair dispatch:
  • RabbitMQ won’t give more than one message to a worker at a time
  • Prevents fast workers from being idle while slow workers are overloaded
  • Messages are distributed evenly across consumers
This is critical for the Sentinel service which performs intensive analysis.

Docker Configuration

RabbitMQ runs as a Docker container with the management plugin enabled:
docker-compose.yml
rabbitmq:
  image: rabbitmq:3-management-alpine
  container_name: message_broker
  ports:
    - "5672:5672"   # AMQP protocol
    - "15672:15672" # Management UI
  environment:
    - RABBITMQ_DEFAULT_USER=admin
    - RABBITMQ_DEFAULT_PASS=admin123
  healthcheck:
    test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
    interval: 10s
    timeout: 5s
    retries: 3
  networks:
    - argos-network

Management UI

Access the RabbitMQ Management UI at http://localhost:15672 Default Credentials:
  • Username: admin
  • Password: admin123
Change these credentials for production deployments!

Monitoring and Management

View Queues

Monitor queue depth, consumer count, and message rates in the Management UI

Check Bindings

Verify exchange-to-queue bindings and routing key patterns

Message Tracing

Enable tracing to debug message routing issues

Performance Metrics

Track message publish/delivery rates and memory usage

Troubleshooting

Symptoms: Services fail to start with connection errorsSolutions:
  • Verify RabbitMQ container is running: docker ps
  • Check health status: docker logs message_broker
  • Ensure port 5672 is accessible
  • Verify network connectivity between containers
Symptoms: Messages accumulate in queuesSolutions:
  • Check consumer count in Management UI
  • Verify listeners are registered: check application logs
  • Ensure @RabbitListener annotations are present
  • Check for exceptions in consumer methods
Symptoms: Messages sent but not receivedSolutions:
  • Verify routing key matches binding pattern
  • Check exchange type (Topic vs Direct)
  • Use Management UI to trace message flow
  • Verify queue bindings are correct

Build docs developers (and LLMs) love