Files
git.stella-ops.org/docs/router/transports/inmemory.md
StellaOps Bot e6c47c8f50 save progress
2025-12-28 23:49:56 +02:00

7.2 KiB

InMemory Transport

The InMemory transport provides zero-latency, in-process communication for development, testing, and scenarios where services run in the same process.

Overview

Property Value
Plugin Assembly StellaOps.Router.Transport.InMemory.dll
Transport Name inmemory
Latency Sub-microsecond
Use Case Development, testing, embedded scenarios

Configuration

router.yaml

Router:
  Transport:
    Type: inmemory
    InMemory:
      MaxPendingMessages: 10000
      MessageTimeout: "00:01:00"

microservice.yaml

routers:
  - host: localhost
    port: 0               # Port ignored for InMemory
    transportType: InMemory
    priority: 1

Environment Variables

ROUTER__TRANSPORT__TYPE=inmemory

Options Reference

Option Type Default Description
MaxPendingMessages int 10000 Maximum queued messages before backpressure
MessageTimeout TimeSpan 00:01:00 Timeout for pending messages
PreserveMessageOrder bool true Guarantee message ordering

Architecture

The InMemory transport uses a shared InMemoryConnectionRegistry singleton that enables direct in-process communication:

┌─────────────────────────────────────────────────────────────────┐
│                        Single Process                            │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                InMemoryConnectionRegistry                   ││
│  │                     (Singleton)                             ││
│  │                                                              ││
│  │  ┌────────────────┐      ┌─────────────────────────────┐   ││
│  │  │ Service A      │      │ Service B                   │   ││
│  │  │ (InMemoryClient│◄────►│ (InMemoryServer)            │   ││
│  │  │  endpoints)    │      │                              │   ││
│  │  └────────────────┘      └─────────────────────────────┘   ││
│  │                                                              ││
│  │  Messages passed directly via                               ││
│  │  ConcurrentQueue<T> - no serialization                      ││
│  └──────────────────────────────────────────────────────────────┘│
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Use Cases

Development

Run Gateway and microservices in the same process:

var builder = WebApplication.CreateBuilder(args);

// Register InMemory transport (shared between gateway and services)
builder.Services.AddInMemoryTransport();

// Add gateway
builder.Services.AddRouterGateway(builder.Configuration);

// Add microservice in same process
builder.Services.AddStellaMicroservice(options =>
{
    options.ServiceName = "order-service";
    options.Version = "1.0.0";
});

var app = builder.Build();
app.UseRouterGateway();
app.Run();

Integration Testing

public class OrderServiceTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;

    public OrderServiceTests(WebApplicationFactory<Program> factory)
    {
        _factory = factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                // Use InMemory transport for tests
                services.Configure<RouterOptions>(opts =>
                    opts.Transport.Type = "inmemory");
            });
        });
    }

    [Fact]
    public async Task CreateOrder_ReturnsOrderId()
    {
        var client = _factory.CreateClient();
        var response = await client.PostAsJsonAsync("/orders", new
        {
            CustomerId = "CUST-001",
            Amount = 99.99m
        });

        response.EnsureSuccessStatusCode();
        var result = await response.Content.ReadFromJsonAsync<OrderResponse>();
        Assert.NotNull(result?.OrderId);
    }
}

Embedded Scenarios

For single-binary deployments:

// All services compiled into one executable
var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddInMemoryTransport();

        // Register all microservice handlers
        services.AddScoped<CreateOrderEndpoint>();
        services.AddScoped<GetOrderEndpoint>();
        services.AddScoped<CreateInvoiceEndpoint>();
    })
    .Build();

Performance Characteristics

Metric Typical Value
Latency (p50) < 0.1ms
Latency (p99) < 0.5ms
Throughput 500,000+ rps
Memory overhead Minimal

Zero serialization, direct object passing

Limitations

  1. Single process only: Cannot communicate across process boundaries
  2. No persistence: Messages lost on process termination
  3. No distribution: Cannot scale to multiple nodes
  4. Shared memory: Large messages consume process memory

When to Use InMemory

Scenario Use InMemory?
Local development Yes
Unit testing Yes
Integration testing Yes
Single-binary deployment Yes
Multi-node deployment No - use TCP/TLS
Production load testing No - use production transport

Transitioning to Production

When moving from development to production:

# Development (appsettings.Development.json)
Router:
  Transport:
    Type: inmemory

# Production (appsettings.Production.json)
Router:
  Transport:
    Type: tls
    Tls:
      Port: 5101
      CertificatePath: /certs/server.pfx

No code changes required - just configuration.

Troubleshooting

Messages Not Being Delivered

  1. Verify both client and server use InMemory transport
  2. Check InMemoryConnectionRegistry is registered as singleton
  3. Ensure services are registered in same DI container

Memory Growing

  1. Check MaxPendingMessages limit
  2. Verify consumers are processing messages
  3. Monitor for message timeout (messages queued too long)

Order Not Preserved

  1. Set PreserveMessageOrder: true
  2. Ensure single consumer per endpoint
  3. Don't use parallel processing in handlers

See Also