KubeMQ
Client SDKsNode.jsHow-to guidesEvents

Multiple Subscribers

Deliver the same KubeMQ events to multiple independent subscribers in Node.js, fanning each message out to every listener.

Overview

Fan-out delivery lets several independent consumers each get their own copy of every event published on a channel — the pattern behind broadcasting a notification to every connected service or feeding the same stream to a cache invalidator and a metrics collector at once. Reach for it whenever multiple, unrelated pieces of code all need to react to the same event, rather than compete for it.

It works by calling subscribeToEvents more than once for the same channel while leaving the group option empty. Each call opens its own stream, and the broker treats every subscriber with no group as broadcast: publishing one event delivers it to every open stream — the opposite of a consumer group, where subscribers sharing a group name split events among themselves for load balancing.

Gotchas: Events pub/sub has no durability — a subscriber that hasn't finished subscribing yet, or that disconnects, simply misses events published in that window; there's no redelivery. Mixing a non-empty group into one subscriber on the same channel silently turns broadcast into load-balancing for it. And because delivery is fully concurrent, shared state your callbacks touch needs its own synchronization.

Prerequisites

  • KubeMQ server running on localhost:50000
  • Node.js SDK installed (npm install kubemq-js)

Code

multiple-subscribers.ts
/**
 * Example: Multiple Subscribers on the Same Channel
 *
 * Demonstrates that multiple subscribers on the same channel each receive
 * a copy of every published event (fan-out). Use the `group` option for
 * load-balanced (competing consumer) behavior instead.
 *
 * Prerequisites:
 *   - KubeMQ server running on localhost:50000
 *
 * Run: npx tsx examples/events/multiple-subscribers.ts
 */
import { KubeMQClient, createEventMessage } from 'kubemq-js';

async function main(): Promise<void> {
  const client = await KubeMQClient.create({
    address: 'localhost:50000',
    clientId: 'js-events-multiple-subscribers-client',
  });

  try {
    // Both subscribers receive every event (fan-out).
    const sub1 = client.subscribeToEvents({
      channel: 'js-events.multiple-subscribers',
      onEvent: (event) => {
        console.log('[Subscriber A]', new TextDecoder().decode(event.body));
      },
      onError: (err) => {
        console.error('Sub A error:', err.message);
      },
    });

    const sub2 = client.subscribeToEvents({
      channel: 'js-events.multiple-subscribers',
      onEvent: (event) => {
        console.log('[Subscriber B]', new TextDecoder().decode(event.body));
      },
      onError: (err) => {
        console.error('Sub B error:', err.message);
      },
    });

    // Allow subscriptions to fully establish on the server.
    await new Promise((resolve) => setTimeout(resolve, 1000));

    await client.sendEvent(
      createEventMessage({ channel: 'js-events.multiple-subscribers', body: 'cpu_usage=72%' }),
    );

    await new Promise((resolve) => setTimeout(resolve, 1000));

    sub1.cancel();
    sub2.cancel();
  } finally {
    await client.close();
  }
}

main().catch(console.error);

How It Works

  • sub1 and sub2 both call subscribeToEvents() on the same channel with no group option — this is fan-out mode: every published event is delivered to all active subscribers independently.
  • The 1-second wait after subscribing ensures both gRPC streams are registered on the server before the single event is published.
  • Because the SDK callbacks run on the Node.js event loop sequentially, both [Subscriber A] and [Subscriber B] lines appear in output for the single sent event.
  • To switch to competing-consumer (load-balanced) behavior instead, set group: 'workers' on both subscriptions.

Was this page helpful?

On this page