Back to Blog
devops10 min read

Microservices Architecture with Docker and Message Queues

Design patterns for building microservices — service decomposition, async communication with RabbitMQ, circuit breakers, distributed tracing, and observability.

V
By Ventra Rocket
·Published on 15 February 2026
#Microservices#Docker#RabbitMQ#Architecture#DevOps

Microservices enable independent deployment and scaling. This guide covers patterns Ventra Rocket uses in production microservice systems.

When to Use Microservices

Use microservices when:

  • Components have different scaling needs
  • Teams need independent deployments
  • There are distinct domain boundaries

Start with a monolith and extract services when boundaries become clear.

1. Service Decomposition

E-commerce Platform
├── user-service       — authentication, profiles
├── product-service    — catalog, inventory
├── order-service      — orders, cart
├── payment-service    — billing
├── notification-service — email, SMS
└── analytics-service  — reporting

Each service:

  • Has its own database (database-per-service)
  • Exposes a well-defined API
  • Can be deployed independently

2. Docker Compose for Local Dev

version: "3.9"
services:
  user-service:
    build: ./user-service
    environment:
      - DATABASE_URL=postgres://user-db/users
    depends_on:
      - user-db

  order-service:
    build: ./order-service
    environment:
      - DATABASE_URL=postgres://order-db/orders
      - RABBITMQ_URL=amqp://rabbitmq
    depends_on:
      - order-db
      - rabbitmq

  rabbitmq:
    image: rabbitmq:3-management-alpine
    ports:
      - "15672:15672"

3. Async Communication with RabbitMQ

import amqp from "amqplib";

// Publisher — order-service
async function publishOrderCreated(order: Order) {
  const conn = await amqp.connect(process.env.RABBITMQ_URL!);
  const channel = await conn.createChannel();
  await channel.assertExchange("orders", "topic", { durable: true });
  channel.publish(
    "orders",
    "order.created",
    Buffer.from(JSON.stringify(order)),
    { persistent: true }
  );
}

// Consumer — notification-service
channel.consume("notification.order.created", async (msg) => {
  if (!msg) return;
  const order = JSON.parse(msg.content.toString());
  await sendOrderConfirmationEmail(order);
  channel.ack(msg);
});

4. Circuit Breaker Pattern

class CircuitBreaker {
  private failures = 0;
  private state: "closed" | "open" | "half-open" = "closed";
  private nextAttempt = Date.now();

  constructor(private threshold = 5, private timeout = 30_000) {}

  async call<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === "open" && Date.now() < this.nextAttempt) {
      throw new Error("Circuit breaker open");
    }
    try {
      const result = await fn();
      this.failures = 0;
      this.state = "closed";
      return result;
    } catch (err) {
      this.failures++;
      if (this.failures >= this.threshold) {
        this.state = "open";
        this.nextAttempt = Date.now() + this.timeout;
      }
      throw err;
    }
  }
}

5. Distributed Tracing

import { trace, SpanStatusCode } from "@opentelemetry/api";

const tracer = trace.getTracer("order-service");

async function createOrder(userId: string, items: OrderItem[]) {
  return tracer.startActiveSpan("createOrder", async (span) => {
    span.setAttributes({ "user.id": userId, "items.count": items.length });
    try {
      const order = await db.orders.create({ userId, items });
      await publishOrderCreated(order);
      span.setStatus({ code: SpanStatusCode.OK });
      return order;
    } catch (err) {
      span.recordException(err as Error);
      span.setStatus({ code: SpanStatusCode.ERROR });
      throw err;
    } finally {
      span.end();
    }
  });
}

Conclusion

Microservices pay off when domains are large enough to justify the complexity. Use message queues for events, circuit breakers for resilience, distributed tracing for observability. Ventra Rocket has migrated multiple monoliths to microservices, achieving independent deployment cycles.

Related Articles

Microservices Architecture with Docker and Message Queues | Ventra Rocket