Fan-Out
Fan out KubeMQ Events to multiple subscribers at once with the Java SDK so every consumer receives each message.
Overview
Fan-out is the default delivery behavior of KubeMQ Events pub/sub: when subscribers don't join a consumer group, every subscriber gets its own independent copy of each published event. Reach for it whenever several unrelated services need to react to the same occurrence — an order placed, a config change, an audit event — without the publisher knowing or caring who's listening, and without one subscriber's slowness affecting another's delivery.
The mechanism is simply omission: building an EventsSubscription without calling .group(...) puts that subscription in broadcast mode instead of load-balanced mode. publishEvent() doesn't change at all — the publisher sends once, and the broker independently pushes a copy to every active subscriber on the channel.
Gotchas: fan-out is opt-out by default, so a typo'd or accidentally shared group name silently turns broadcast into competing-consumer load-balancing with no error raised. Events are not persisted — a subscriber that hasn't called subscribeToEvents() yet when publishEvent() runs misses that event permanently (use Events Store if you need replay). And publishEvent() is fire-and-forget — it returns as soon as the broker accepts the send, not after subscribers process it — so a publisher can outrun subscription setup on a cold start, which is why this sample sleeps briefly before publishing.
Prerequisites
- KubeMQ server running on
localhost:50000 - Java SDK installed (
implementation 'io.kubemq.sdk:kubemq-sdk-Java:3.1.1'(Gradle) or Maven dependency from Getting Started)
Code
package io.kubemq.example.patterns;
import io.kubemq.sdk.common.ServerInfo;
import io.kubemq.sdk.pubsub.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Fan-Out Pattern Example
*
* Demonstrates the fan-out pattern where one publisher sends to multiple subscribers.
*/
public class FanOutExample {
private static final String ADDRESS = "localhost:50000";
private static final String CLIENT_ID = "java-patterns-fan-out-client";
private static final String CHANNEL = "java-patterns.fan-out";
public static void main(String[] args) throws InterruptedException {
// Create a client connected to the KubeMQ server
PubSubClient client = PubSubClient.builder().address(ADDRESS).clientId(CLIENT_ID).build();
ServerInfo info = client.ping();
System.out.println("Connected to: " + info.getHost());
// Create the events channel
client.createEventsChannel(CHANNEL);
// Subscribe multiple handlers (each receives all messages)
int numSubscribers = 3;
int numMessages = 3;
AtomicInteger[] counts = new AtomicInteger[numSubscribers];
CountDownLatch latch = new CountDownLatch(numSubscribers * numMessages);
EventsSubscription[] subs = new EventsSubscription[numSubscribers];
for (int i = 0; i < numSubscribers; i++) {
final int id = i + 1;
counts[i] = new AtomicInteger(0);
final AtomicInteger counter = counts[i];
subs[i] = EventsSubscription.builder()
.channel(CHANNEL)
.onReceiveEventCallback(event -> {
counter.incrementAndGet();
System.out.println(" Subscriber " + id + ": " + new String(event.getBody()));
latch.countDown();
})
.onErrorCallback(err -> {}).build();
// Subscribe each subscriber to the channel
client.subscribeToEvents(subs[i]);
}
Thread.sleep(500);
// Publish messages (fan-out to all subscribers)
System.out.println("Publishing " + numMessages + " messages to " + numSubscribers + " subscribers...\n");
for (int i = 1; i <= numMessages; i++) {
client.publishEvent(EventMessage.builder()
.id("fan-" + i).channel(CHANNEL)
.body(("Broadcast #" + i).getBytes()).build());
Thread.sleep(100);
}
latch.await(5, TimeUnit.SECONDS);
System.out.println("\nResults:");
for (int i = 0; i < numSubscribers; i++) {
System.out.println(" Subscriber " + (i + 1) + ": " + counts[i].get() + " messages");
}
// Clean up resources
for (EventsSubscription s : subs) { s.cancel(); }
client.deleteEventsChannel(CHANNEL);
client.close();
}
}
How It Works
- A single
PubSubClientcreates threeEventsSubscriptionobjects on the same channel without agroup()— every subscriber receives every published message independently, which is the fan-out property. - Each subscriber is wired with its own
AtomicIntegercounter and shares aCountDownLatchinitialized tonumSubscribers * numMessages;latch.await()blocks main until all deliveries are confirmed. publishEvent()is fire-and-forget: it enqueues the gRPC send and returns immediately without waiting for subscriber acknowledgements.Thread.sleep(500)after subscribing gives the SDK time to register all three subscriptions with the broker before publishing begins; this avoids race conditions in examples but is not needed in long-running services.
Related
Was this page helpful?