Server Sent Events

Server Sent Events (SSE) allow you to publish data over a long-lived response to a client.

To publish, create a handler and then create an SsePublisherpublisher using the SsePublisher.start(request, response) method.

The following example creates a thread that will send 1000 messages to the browser and then close the stream:

public class ServerSentEventsExample {
    public static void main(String[] args) {
        MuServer server = httpServer()
            .addHandler(Method.GET, "/sse/counter", (request, response, pathParams) -> {

                SsePublisher publisher = SsePublisher.start(request, response);
                new Thread(() -> count(publisher)).start();

            .addHandler(ResourceHandlerBuilder.fileOrClasspath("src/main/resources/samples", "/samples"))
        System.out.println("Open " + server.uri().resolve("/sse.html") + " to see some numbers.");

    public static void count(SsePublisher publisher) {
        for (int i = 0; i < 100; i++) {
            try {
                publisher.send("Number " + i);
            } catch (Exception e) {
                // The user has probably disconnected so stopping
(see full file)

This page connects to the endpoint above and prints each message as it comes in:

<p>Connection status: <span class="status">Not started. <input type="button" value="start" id="startButton"></span></p>
<div class="messages"></div>

    document.getElementById('startButton').addEventListener('click', _ => {
        let $ = document.querySelector.bind(document);
        let status = $('.status');
        let messages = $('.messages');
        let source = new EventSource('/sse/counter');

        source.addEventListener('open', e => {
            console.log('Connected', e);
            status.textContent = 'Connected';

        source.addEventListener('error', e => {
            console.log('error', e);
            status.textContent = 'Error';

        source.addEventListener('message', e => {
(see full file)

Note that in these examples a thread is kept open per client, and each call to send is blocking. See AsyncSsePublisherfor an async version that has callbacks.

Try it out

Connection status: Not started.


JAX RS SSE Publishing

If using JAX-RS resources, you can use an SSE broadcaster to broadcast to multiple clients.

In the following example, there is a single incrementing counter and clients can register to updates to the counter. Note that no matter how many clients are connected, they will all share the same counter and only a single thread is used.

public class JaxRSBroadcastExample {

    public static void main(String[] args) {
        TimeResource timeResource = new TimeResource();

        MuServer server = httpServer()
            .addHandler(ResourceHandlerBuilder.fileOrClasspath("src/main/resources/samples", "/samples"))
        System.out.println("Example started at " + server.uri().resolve("/sse.html"));


class TimeResource {

    long count = 0;
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    Sse sse = MuRuntimeDelegate.createSseFactory();
    SseBroadcaster broadcaster = sse.newBroadcaster();

    public void registerListener(@Context SseEventSink eventSink) {

    public void start() {
        executor.scheduleAtFixedRate(() -> {
            String data = "Number " + count;
        }, 0, 100, TimeUnit.MILLISECONDS);

(see full file)

The same HTML as for the previous example can be used.