Table of Contents

Slow Consumers

When a subscriber can't keep up with the rate of incoming messages, its internal bounded channel fills up. By default, new messages are dropped when this happens. This is aligned with NATS at-most-once delivery.

Detecting Dropped Messages

The MessageDropped event fires every time a message is dropped from a subscription's internal channel:

await using NatsConnection nc = new NatsConnection();

nc.MessageDropped += (sender, args) =>
{
    Console.WriteLine($"Dropped message on '{args.Subject}' with {args.Pending} pending messages");
    return default;
};

Detecting Slow Consumers

The SlowConsumerDetected event (added in v2.7.2) fires once per slow consumer episode. It resets after the subscription catches up (channel drains), so it will fire again if the subscription falls behind a second time:

await using NatsConnection nc = new NatsConnection();

nc.SlowConsumerDetected += (sender, args) =>
{
    Console.WriteLine($"Slow consumer detected on '{args.Subscription.Subject}'");
    return default;
};

Tuning Channel Capacity

Each subscription has an internal bounded channel with a default capacity of 1024 messages. You can tune this globally or per subscription:

// Set global default capacity
NatsOpts opts = new NatsOpts { SubPendingChannelCapacity = 4096 };
await using NatsConnection nc = new NatsConnection(opts);

// Override capacity for a specific subscription
NatsSubOpts subOpts = new NatsSubOpts
{
    ChannelOpts = new NatsSubChannelOpts { Capacity = 8192 },
};

await foreach (NatsMsg<string> msg in nc.SubscribeAsync<string>("events.>", opts: subOpts))
{
    Console.WriteLine($"Received: {msg.Data}");
}

Channel Full Mode

The SubPendingChannelFullMode option controls what happens when the channel is full:

  • BoundedChannelFullMode.DropNewest (default for NatsConnection) - newest messages are dropped
  • BoundedChannelFullMode.Wait (default for NatsClient) - backpressure is applied, but the server may disconnect you as a slow consumer
Warning

Using BoundedChannelFullMode.Wait prevents message loss at the client level, but if the subscriber can't keep up, the NATS server itself may disconnect the client as a slow consumer.

Suppressing Warnings

By default, a warning is logged once per slow consumer episode. You can suppress these logs while still receiving the events:

NatsOpts opts = new NatsOpts
{
    SuppressSlowConsumerWarnings = true,
};

await using NatsConnection nc = new NatsConnection(opts);

// Events still fire even when log warnings are suppressed
nc.SlowConsumerDetected += (sender, args) =>
{
    Console.WriteLine($"Slow consumer on '{args.Subscription.Subject}'");
    return default;
};