DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • WebSocket vs. Server-Sent Events: Choosing the Best Real-Time Communication Protocol
  • How To Build a Real-Time, Event-Driven Information System
  • Tutorial: How to Build a Progressive Web App (PWA)
  • Reactive Messaging Examples for Quarkus

Trending

  • Start Coding With Google Cloud Workstations
  • Automatic Code Transformation With OpenRewrite
  • Automating Data Pipelines: Generating PySpark and SQL Jobs With LLMs in Cloudera
  • The Human Side of Logs: What Unstructured Data Is Trying to Tell You
  1. DZone
  2. Coding
  3. Tools
  4. How to Build Real-Time Notification Service Using Server-Sent Events (SSE)

How to Build Real-Time Notification Service Using Server-Sent Events (SSE)

For the SSE to work, the server needs to tell the client that the response’s content-type is text/eventstream.

By 
Michal Kapiczynski user avatar
Michal Kapiczynski
·
Oct. 22, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
10.7K Views

Join the DZone community and get the full member experience.

Join For Free

Most of the communication on the Internet comes directly from the clients to the servers. The client usually sends a request, and the server responds to that request. It is known as a client-server model, and it works well in most cases. However, there are some scenarios in which the server needs to send a message to the client without the preceding request.

In such cases, we have a couple of options: we can use short and long polling, webhooks, websockets, or event streaming platforms like Kafka. However, there is another technology, not popularized enough, which in many cases, is just perfect for the job. This technology is the Server-Sent Events (SSE) standard.

What Are Server-Sent Events?

SSE definition states that it is an HTTP standard that allows a web application to handle a unidirectional event stream and receive updates whenever the server emits data. In simple terms, it is a mechanism for unidirectional event streaming.

Browsers Support

It is currently supported by all major browsers except Internet Explorer.

Message Format

The events are just a stream of UTF-8 encoded text data in a format defined by the Specification. The important aspect here is that the format defines the fields that the SSE message should have, but it does not mandate a specific type for the payload, leaving the freedom of choice to the users. 

Java
 




xxxxxxxxxx
1


 
1
{
2

          
3
 "id": "message id <optional>",
4

          
5
 "event": "event type <optional>",
6

          
7
 "data": "event data –plain text, JSON, XML… <mandatory>"
8

          
9
}



SSE Implementation

For the SSE to work, the server needs to tell the client that the response’s content-type is text/eventstream. Next, the server receives a regular HTTP request, and leaves the HTTP connection open until no more events are left or until the timeout occurs. If the timeout occurs before the client receives all the events it expects, it can use the built-in reconnection mechanism to re-establish the connection.

client and server

Simple Endpoint (Flux):

The simplest implementation of the SSE endpoint in Spring can be achieved by:

  • Specifying the produced media type as text/event-stream,
  • Returning Flux type, which is a reactive representation of a stream of events in Java.

@GetMapping(path = "/stream-flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

public Flux<String> streamFlux() {

   return Flux.interval(Duration.ofSeconds(1))

           .map(sequence -> "Flux - " + LocalTime.now().toString());

ServerSentEvent Class

Spring introduced support for SSE specification in version 4.2 together with a ServerSentEvent class. The benefit here is that we can skip the text/event-stream media type explicit specification, as well as we can add metadata such as id or event type.

@GetMapping("/sse-flux-2")

public Flux<ServerSentEvent> sseFlux2() {

   return Flux.interval(Duration.ofSeconds(1))

           .map(sequence -> ServerSentEvent.builder()

                   .id(String.valueOf(sequence))

                   .event("EVENT_TYPE")

                   .data("SSE - " + LocalTime.now().toString())

                   .build());

}


SseEmitter Class:

However, the full power of SSE comes with the SseEmitter class. It allows for asynchronous processing and publishing of the events from other threads. What is more, it is possible to store the reference to SseEmitter and retrieve it on subsequent client calls. This provides a huge potential for building powerful notification scenarios.

@GetMapping("/sse-emitter")

public SseEmitter sseEmitter() {

   SseEmitter emitter = new SseEmitter();

   Executors.newSingleThreadExecutor().execute(() -> {

       try {

           for (int i = 0; true; i++) {

               SseEmitter.SseEventBuilder event = SseEmitter.event()

                       .id(String.valueOf(i))

                       .name("SSE_EMITTER_EVENT")

                       .data("SSE EMITTER - " + LocalTime.now().toString());

               emitter.send(event);

               Thread.sleep(1000);

           }

       } catch (Exception ex) {

           emitter.completeWithError(ex);

       }

   });

   return emitter;


Client example:

Here is a basic SSE client example written in Javascript. It simply defines an EventSource and subscribes to the message event stream in two different ways.

// Declare an EventSource

const eventSource = new EventSource('http://some.url');

// Handler for events without an event type specified

eventSource.onmessage = (e) => {

   // Do something - event data etc will be in e.data

};

// Handler for events of type 'eventType' only

eventSource.addEventListener('eventType', (e) => {

   // Do something - event data will be in e.data,

   // message will be of type 'eventType'

});


SSE vs. Websockets

When it comes to SSE, it is often compared to Websockets due to usage similarities between both of the technologies.

  • Both are capable of pushing data to the client,
  • Websockets are bidirectional – SSE unidirectional,
  • In practice, everything that can be done with SSE, and can also be achieved with Websockets,
  • SSE can be easier,
  • SSE is transported over a simple HTTP connection,
  • Websockets require full duplex-connection and servers to handle the protocol,
  • Some enterprise firewalls with packet inspection have trouble dealing with Websockets – for SSE that’s not the case,
  • SSE has a variety of features that Websockets lack by design, e.g., automatic reconnection, event ids,
  • Only Websockets can send both binary and UTF-8 data, SSE is limited to UTF-8, 
  • SSE suffers from a limitation to the maximum number of open connections (6 per browser + domain). The issue was marked as Won’t fix in Chrome and Firefox.

Use Cases:

use cases

Notification Service Example:

A controller providing a subscribe to events and a publish events endpoints.

Java
 




xxxxxxxxxx
1
45


 
1
@Slf4j
2

          
3
@RestController
4

          
5
@RequestMapping("/events")
6

          
7
@RequiredArgsConstructor
8

          
9
public class EventController {
10

          
11
   public static final String MEMBER_ID_HEADER = "MemberId";
12

          
13
 
14

          
15
   private final EmitterService emitterService;
16

          
17
   private final NotificationService notificationService;
18

          
19
 
20

          
21
   @GetMapping
22

          
23
   public SseEmitter subscribeToEvents(@RequestHeader(name = MEMBER_ID_HEADER) String memberId) {
24

          
25
       log.debug("Subscribing member with id {}", memberId);
26

          
27
       return emitterService.createEmitter(memberId);
28

          
29
   }
30

          
31
 
32

          
33
   @PostMapping
34

          
35
   @ResponseStatus(HttpStatus.ACCEPTED)
36

          
37
   public void publishEvent(@RequestHeader(name = MEMBER_ID_HEADER) String memberId, @RequestBody EventDto event) {
38

          
39
       log.debug("Publishing event {} for member with id {}", event, memberId);
40

          
41
       notificationService.sendNotification(memberId, event);
42

          
43
   }
44

          
45
}



A service for sending the events:

Java
 




xxxxxxxxxx
1
59


 
1
@Service
2

          
3
@Primary
4

          
5
@AllArgsConstructor
6

          
7
@Slf4j
8

          
9
public class SseNotificationService implements NotificationService {
10

          
11
 
12

          
13
   private final EmitterRepository emitterRepository;
14

          
15
   private final EventMapper eventMapper;
16

          
17
 
18

          
19
   @Override
20

          
21
   public void sendNotification(String memberId, EventDto event) {
22

          
23
       if (event == null) {
24

          
25
           log.debug("No server event to send to device.");
26

          
27
           return;
28

          
29
       }
30

          
31
       doSendNotification(memberId, event);
32

          
33
   }
34

          
35
 
36

          
37
   private void doSendNotification(String memberId, EventDto event) {
38

          
39
       emitterRepository.get(memberId).ifPresentOrElse(sseEmitter -> {
40

          
41
           try {
42

          
43
               log.debug("Sending event: {} for member: {}", event, memberId);
44

          
45
               sseEmitter.send(eventMapper.toSseEventBuilder(event));
46

          
47
           } catch (IOException | IllegalStateException e) {
48

          
49
               log.debug("Error while sending event: {} for member: {} - exception: {}", event, memberId, e);
50

          
51
               emitterRepository.remove(memberId);
52

          
53
           }
54

          
55
       }, () -> log.debug("No emitter for member {}", memberId));
56

          
57
   }
58

          
59
}



To sum up, Server-Sent Events standard is a great technology when it comes to a unidirectional stream of data and often can save us a lot of trouble compared to more complex approaches such as Websockets or distributed streaming platforms.

A full notification service example implemented with the use of Server-Sent Events can be found on my GitHub: https://github.com/mkapiczy/server-sent-events

Sources:

  • https://www.baeldung.com/spring-server-sent-events
  • https://www.w3.org/TR/eventsource/
  • https://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource
  • https://www.telerik.com/blogs/websockets-vs-server-sent-events
  • https://simonprickett.dev/a-look-at-server-sent-events/
Event Server-sent events Notification service Web Service WebSocket UTF-8 Build (game engine)

Published at DZone with permission of Michal Kapiczynski. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • WebSocket vs. Server-Sent Events: Choosing the Best Real-Time Communication Protocol
  • How To Build a Real-Time, Event-Driven Information System
  • Tutorial: How to Build a Progressive Web App (PWA)
  • Reactive Messaging Examples for Quarkus

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!