Building a UI with SSE support

Building a UI with SSE support

In order to complete our use case we need an HTML page with some JavaScript code to communicate with the server. For the sake of conciseness, we will strip all HTML tags and leave only the minimum that is required to achieve a result, as follows:

<body>
<ul id="events"></ul>
<script type="application/javascript">
function add(message) {
    const el = document.createElement("li");
    el.innerHTML = message;
    document.getElementById("events").appendChild(el);
}
var eventSource = new EventSource("/temperature-stream");
eventSource.onmessage = e => { 
    const t = JSON.parse(e.data);
    const fixed = Number(t.value).toFixed(2);
    add('Temperature: ' + fixed + ' C');
}
eventSource.onopen = e => add('Connection opened');
eventSource.onerror = e => add('Connection closed');
</script>
</body>        

Here, we are using the EventSource object pointed at /temperature-stream. This handles incoming messages by invoking the onmessage() function, error handling, and reaction to the stream opening, which are done in the same fashion. We should save this page as index.html and put it in the src/main/resources/static/ folder of our project. By default, Spring Web MVC serves the content of the folder through HTTP. Such behavior could be changed by providing a configuration that extends the WebMvcConfigurerAdapter class.


Verifying application functionality

After rebuilding and completing our application's startup, we should be able to access the mentioned web page in a browser at the following address: https://localhost:8080 (Spring Web MVC uses port 8080 for the web server as the default one. However, this can be changed in the application.properties file using the configuration line server.port=9090). After a few seconds, we may see the following output:

Connection opened
Temperature: 14.71 C
Temperature: 9.67 C
Temperature: 19.02 C
Connection closed
Connection opened
Temperature: 18.01 C
Temperature: 16.17 C        

As we can see, our web page reactively receives events, preserving both client and server resources. It also supports auto-reconnect in the case of network issues or timeouts. As the current solution is not exclusive to JavaScript, we may connect with other clients, for example, curl. By running the next command in a terminal, we receive the following stream of raw, but not formatted, events:

> curl https://localhost:8080/temperature-stream
data:{"value":22.33210856124129}
data:{"value":13.83133638119636}        

Criticism of the solution

At this point, we may praise ourselves for implementing a resilient reactive application using only a few dozen code lines (including HTML and JavaScript). However, the current solution has a few issues. First of all, we are using the Publish-Subscribe infrastructure provided by Spring. In Spring Framework, this mechanism was initially introduced for handling application life cycle events and was not intended for high-load, high-performance scenarios. What would happen when we need thousands or even millions of separate streams instead of one stream of temperature data? Will Spring's implementation be able to handle such a load efficiently?

Furthermore, one significant downside of such an approach lies in the fact that we are using an internal Spring mechanism to define and implement our business logic. This leads to a situation in which some minor changes in the framework may break our application. Besides, it is hard to unit test our business rules without running the application context. It is also reasonable to mention an application that has a lot of methods that are decorated with the @EventListener annotation, and without an explicit script that describes the whole workflow in one concise piece of code.

Furthermore, SseEmitter has a notion for errors and the ends of streams, whereas @EventListener does not. So, to signal the end of the stream or error between components, we have to define some special objects or class hierarchies, and it is easy to forget about handling them. Also, such specific markers may have slightly different semantics in different situations, complicating the solution and reducing the attractiveness of the approach.

One more drawback worth highlighting is that we allocate the thread pool to asynchronously broadcast temperature events. In the case of a genuinely asynchronous and reactive approach (framework), we wouldn't have to do this.

Our temperature sensor generates only one stream of events without regard to how many clients are listening. However, it also creates them when nobody listens. That may lead to a waste of resources, especially when creation actions are resource-hungry. For example, our component may communicate with real hardware and reduce hardware lifespan at the same time.

To address all of these issues, as well as others, we need a reactive library that is specially designed for such purposes. Fortunately, we have a few of these. In the next episode, we will look at RxJava, which was the first widely adopted reactive library and changed the way we build reactive applications using Java.

要查看或添加评论,请登录

samson baraka的更多文章

  • Working with domain services

    Working with domain services

    When modeling a problem domain, we'll certainly face situations where the task at hand does not fit adequately into any…

  • Assuring consistency with aggregates

    Assuring consistency with aggregates

    We've so far seen how valuable entities are to represent things in a problem domain. Also, we saw how value objects are…

  • Enhancing descriptiveness with value objects

    Enhancing descriptiveness with value objects

    Implementing Domain-Driven Design pointed out quite well that we should use value objects to measure, quantify, or…

  • Wrapping Business Rules inside Domain Hexagon

    Wrapping Business Rules inside Domain Hexagon

    Previously we learned about the Domain as the first hexagon in hexagonal architecture. By being the innermost hexagon…

  • Advantages of the hexagonal approach

    Advantages of the hexagonal approach

    If you're looking for a pattern to help you standardize the way software is developed at your company or even in…

  • Framework hexagon

    Framework hexagon

    Things seem well organized with our critical business rules constrained to the Domain hexagon, followed by the…

    1 条评论
  • Application hexagon

    Application hexagon

    So far, we've been discussing how the Domain hexagon encapsulates business rules with entities and value objects. But…

  • Understanding the hexagonal architecture 2

    Understanding the hexagonal architecture 2

    In the last episode we introduced the domain hexagon. Now, let's talk about the components that comprise this hexagon.

  • Understanding the hexagonal architecture

    Understanding the hexagonal architecture

    Create your application to work without either a UI or a database so that you can run automated regression tests…

  • Why Hexagonal Architecture?

    Why Hexagonal Architecture?

    Software that's not well organized and lacks sound software architecture principles may work just fine but develop…

社区洞察

其他会员也浏览了