Skip to content

Backends

Strata uses a pluggable backend system so the same service code can run on different message queue implementations. All services that need to communicate with each other must share the same backend, but you can have multiple service or client instances connected to different backends in the same process.

Strata ships with three built-in backends and supports using or writing custom ones.

Built-in Backends

Redis Lists (redis)

The default and recommended backend. Uses Redis lists for queuing, Redis pub/sub for commands, and Redis sets for service discovery.

How it works:

  • Sending a request: RPUSH Requests:<ServiceGroup> "{ ... }"
  • Listening for requests: BLPOP Requests:<ServiceGroup> <timeout>
  • Sending a response: RPUSH <responseQueue> "{ ... }"
  • Listening for responses: BLPOP <responseQueue> <timeout>

Simple, reliable, and well-understood. Messages are delivered to exactly one consumer (whichever pops first), giving you natural load balancing across service instances.

Configuration:

typescript
const service = new StrataService({
    service: { serviceGroup: 'UserService' },
    backend: {
        type: 'redis',
        redis: {
            host: 'localhost',
            port: 6379,
        },
    },
});

When to use: This is the default for most deployments. Simple, low overhead, and covers the vast majority of use cases.

Redis Streams (redis-streams)

An alternative backend that uses Redis Streams instead of lists.

How it works:

  • Sending a request: XADD Requests:<ServiceGroup> * msg "{ ... }"
  • Listening for requests: XREADGROUP GROUP <ServiceGroup> <ServiceID> COUNT <concurrency> BLOCK 0 STREAMS Requests:<ServiceGroup> >
  • Sending a response: Pipelines XADD (the response) and XACK (the request) as a single transaction.
  • Listening for responses: XREAD BLOCK 0 STREAMS Responses:<ServiceGroup>:<ServiceID>

Redis Streams provide consumer groups, message acknowledgment, and crash recovery semantics. However, Strata does not currently expose these capabilities at the framework level, so in practice the streams backend adds overhead without additional benefit over the lists backend.

Configuration:

typescript
const service = new StrataService({
    service: { serviceGroup: 'UserService' },
    backend: {
        type: 'redis-streams',
        redis: {
            host: 'localhost',
            port: 6379,
            db: 0,
        },
    },
});

When to use: If you have a specific reason to use Redis Streams (existing infrastructure, future plans for stream-level features). Otherwise, prefer the Redis lists backend.

Null (null)

A backend that does nothing. It accepts all method calls but doesn't send or receive any messages. Intended for testing.

Configuration:

typescript
const service = new StrataService({
    service: { serviceGroup: 'TestService' },
    backend: { type: 'null' },
});

When to use: Unit tests where you want to test your operation handlers and middleware without needing a running Redis instance. The null backend lets you instantiate a full StrataService with no external dependencies.

Common Backend Configuration

All backends share a common set of configuration options:

typescript
interface BackendConfig
{
    type : string;                    // Which backend to use
    discovery ?: DiscoveryConfig;     // Service discovery settings
    validateEnvelopes ?: boolean;     // Envelope validation (default: true)
}

Envelope Validation

All backends include built-in envelope validation that checks message structure before processing. Enabled by default with near-zero performance overhead (0-2%).

typescript
backend: {
    type: 'redis',
    validateEnvelopes: true,   // Default -- leave it on
}

See Envelope Validation for details on what gets validated and how errors are handled.

Service Discovery

The Redis-based backends support service discovery. When enabled, each service instance periodically registers itself, and clients can query for available services.

typescript
backend: {
    type: 'redis',
    discovery: {
        enabled: true,
        interval: 30,   // Registration interval in seconds
        ttl: 90,         // Key expiration in seconds
        db: 0,           // Redis DB for discovery data
    },
}

Queue Naming

Both Redis backends use the convention Requests:<ServiceGroup> for request queues. In environments where multiple developers share the same Redis instance, append the hostname to the service group in your config:

yaml
service:
  serviceGroup: "UserService.$HOSTNAME"

This gives each developer an isolated queue.

Custom Backends

Need a different transport? You can plug in any messaging system -- AMQP, Kafka, gRPC, in-memory, whatever fits your infrastructure.