Skip to content

Features

Namastack Outbox for Spring Boot provides a comprehensive set of features to implement the Outbox Pattern in distributed systems with reliability, scalability, and ease of use.

Core Features

Transactional Outbox Pattern

Zero Message Loss

The library ensures that domain events are never lost by storing them in the same database transaction as your business data. This guarantees consistency between your domain state and published events.

Benefits

  • ACID Compliance: Events are saved atomically with business data
  • Consistency Guarantee: No partial updates or lost events
  • Failure Recovery: System crashes don't result in data loss
  • Exactly-once semantics: Events are processed reliably

How it Works

sequenceDiagram
    participant A as Application
    participant DB as Database
    participant O as Outbox
    participant P as Processor

    A->>DB: Begin Transaction
    A->>DB: Save Business Data
    A->>O: Save Event
    DB->>A: Commit Transaction
    P->>O: Poll Events
    P->>P: Process Event
    P->>O: Mark Complete

Distributed Locking

Concurrent Processing Prevention

Each aggregate gets its own distributed lock to prevent multiple instances from processing the same events simultaneously while allowing different aggregates to be processed in parallel.

  • Per-Aggregate Locking: Fine-grained control prevents bottlenecks
  • Automatic Expiration: Locks expire to prevent deadlocks
  • Lock Renewal: Active processors can extend their locks
  • Optimistic Locking: Prevents race conditions during renewal
  • Horizontal Scaling: Multiple instances can work on different aggregates
outbox:
  locking:
    extension-seconds: 300     # Lock duration (5 minutes)
    refresh-threshold: 60      # Renew when < 60s remaining

Event Ordering

Guaranteed Processing Order

Events for the same aggregate are always processed in creation order, ensuring business logic consistency and preventing race conditions.

Key Benefits:

  • Aggregate Consistency: Events within an aggregate maintain order
  • Business Logic Safety: Dependent events process in correct sequence
  • Parallel Aggregates: Different aggregates process independently
  • Scalable Design: No global ordering bottlenecks

Control how the scheduler handles failures within aggregates:

Stop on First Failure

outbox:
  processing:
    stop-on-first-failure: true
  • When one event fails, processing stops for remaining events in that aggregate
  • Maintains strict event ordering within aggregates
  • Prevents cascading issues from dependent events
  • Recommended: When events within an aggregate have dependencies
outbox:
  processing:
    stop-on-first-failure: false
  • Failed events don't block independent events in the same aggregate
  • Maximizes throughput for independent events
  • Recommended: When events within an aggregate are independent

Behavior Comparison:

Configuration Event 1 Event 2 Event 3 Result
true (default) Success Fails Skipped Event 2 retried, Event 3 waits
false Success Fails Success Event 2 retried independently

Advanced Configuration

Retry Mechanisms

The library provides sophisticated retry strategies to handle transient failures gracefully.

outbox:
  retry:
    policy: "fixed"
    max-retries: 5
    fixed:
      delay: 5000  # 5 seconds between retries

Use Case: Simple scenarios with consistent retry intervals

outbox:
  retry:
    policy: "exponential"
    max-retries: 10
    exponential:
      initial-delay: 1000    # Start with 1 second
      max-delay: 300000      # Cap at 5 minutes
      multiplier: 2.0        # Double each time

Retry Schedule: 1s → 2s → 4s → 8s → 16s → ... (up to max-delay)

outbox:
  retry:
    policy: "jittered"
    max-retries: 7
    jittered:
      base-policy: exponential
      jitter: 1000           # Add 0-1000ms random delay
    exponential:
      initial-delay: 2000
      max-delay: 60000
      multiplier: 2.0

Benefits: Prevents thundering herd problems in high-traffic systems

Monitoring & Observability

Including the Metrics Module

Add Dependency

To enable monitoring and observability features, include the namastack-outbox-metrics module in your project:

dependencies {
    implementation("io.namastack:namastack-outbox-starter-jpa")
    implementation("io.namastack:namastack-outbox-metrics")

    // For Prometheus endpoint (optional)
    implementation("io.micrometer:micrometer-registry-prometheus")
}
<dependencies>
    <dependency>
        <groupId>io.namastack</groupId>
        <artifactId>namastack-outbox-starter-jpa</artifactId>
        <version>${namastack-outbox.version}</version>
    </dependency>
    <dependency>
        <groupId>io.namastack</groupId>
        <artifactId>namastack-outbox-metrics</artifactId>
        <version>${namastack-outbox.version}</version>
    </dependency>

    <!-- For Prometheus endpoint (optional) -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
</dependencies>

Built-in Metrics

Micrometer Integration

The namastack-outbox-metrics module provides automatic integration with Spring Boot Actuator and Micrometer.

Metric Description Tags
outbox.records.count Number of outbox records status=new\|failed\|completed

Endpoints:

  • /actuator/metrics/outbox.records.count
  • /actuator/prometheus (if Prometheus enabled)
outbox_records_count{status="new"} 42
outbox_records_count{status="failed"} 3  
outbox_records_count{status="completed"} 1337
# Get current metrics
curl http://localhost:8080/actuator/metrics/outbox.records.count

# Prometheus endpoint
curl http://localhost:8080/actuator/prometheus | grep outbox

Status Monitoring

Monitor outbox status programmatically:

@Service
class OutboxMonitoringService(
    private val outboxRepository: OutboxRecordRepository
) {
    fun getPendingEvents(): List<OutboxRecord> = 
        outboxRepository.findPendingRecords()

    fun getFailedEvents(): List<OutboxRecord> = 
        outboxRepository.findFailedRecords()

    fun getCompletedEvents(): List<OutboxRecord> = 
        outboxRepository.findCompletedRecords()
}

Performance Features

High Throughput

Optimized for Scale

  • Batch Processing: Multiple events processed efficiently
  • Connection Pooling: Database connections managed optimally
  • Minimal Overhead: Lightweight processing with low latency
  • Concurrent Aggregates: Parallel processing across different aggregates

Race Condition Safety

  • Uses database-level optimistic locking
  • Prevents concurrent modifications
  • Automatic retry on version conflicts
  • No performance penalty for read operations
  • Different aggregates process independently
  • No global locks or bottlenecks
  • Scales horizontally across instances
  • Maintains per-aggregate ordering guarantees

Developer Experience

Easy Integration

Minimal Setup Required

  1. Add Dependency: Single JAR includes everything needed
  2. Enable Annotation: @EnableOutbox activates all features
  3. Configure Database: Automatic schema creation available
  4. Implement Processor: Simple interface for event handling
val outboxRecord = OutboxRecord.Builder()
    .aggregateId(order.id.toString())
    .eventType("OrderCreated")
    .payload(objectMapper.writeValueAsString(event))
    .build(clock)
val outboxRecord = OutboxRecord.restore(
    id = UUID.randomUUID().toString(),
    aggregateId = order.id.toString(),
    eventType = "OrderCreated",
    payload = objectMapper.writeValueAsString(event),
    createdAt = OffsetDateTime.now(clock),
    status = OutboxRecordStatus.NEW,
    completedAt = null,
    retryCount = 0,
    nextRetryAt = OffsetDateTime.now(clock)
)

Testing Support

  • Unit Tests: All components with high coverage
  • Integration Tests: Real database and locking scenarios
  • Concurrency Tests: Race condition validation
  • Performance Tests: High-throughput scenarios
./gradlew test

Database Support

Broad Compatibility

Works with any JPA-supported database:

  • PostgreSQL (Recommended)
  • MySQL
  • H2 (Development/Testing)
  • SQL Server
  • :material-oracle: Oracle
  • And any other JPA-compatible database
# Automatic schema creation
outbox:
  schema-initialization:
    enabled: true

Or use manual SQL scripts for production deployments.

Reliability Guarantees

What Namastack Outbox for Spring Boot Guarantees

  • At-least-once delivery: Events will be processed at least once
  • Ordering per aggregate: Events for the same aggregate are processed in order
  • Failure recovery: System failures don't result in lost events
  • Scalability: Multiple instances can process different aggregates concurrently
  • Consistency: Database transactions ensure data integrity
  • Eventual consistency: Failed events are automatically retried

What Namastack Outbox for Spring Boot Does NOT Guarantee

  • Exactly-once delivery: Events may be processed multiple times (your handlers should be idempotent)
  • Global ordering: No ordering guarantee across different aggregates
  • Real-time processing: Events are processed asynchronously with configurable delays

Next Steps

Ready to get started? Check out the Quick Start Guide to integrate Namastack Outbox for Spring Boot into your application.