| Did you know ... | Search Documentation: |
| Providing Server-Sent Events (sse) |
Server-Sent Events allows for setting up a simple event stream from the server to the client. It can serve roles similar to long polling and web sockets, enabling the server to notify its clients on some event. Long polling uses a normal HTTP (usually) GET request that blocks for a long time on the server. The server finishes the request when it wants to notify the client or after some time (e.g., a minute) to avoid a timeout on the client or some proxy. After receiving an event or timeout, the client repeats the request. Web sockets upgrade a the socket used for a normal HTTP request to create a bi-directional open communication channel that exchanges encapsulated messages in both directions. Server-Sent Events open a normal HTTP channel over which the server can sent simple text messages using a format similar to the HTTP header: a sequence of Name: Value lines followed by two newlines. Unlike long polling, the request does not complete after a message.
Following the MDN documentation above, an SSE request can be served using the simple example below, which generates an event counting every minute. The handler is declared to process the request on a new thread and to disable the request timeout, as the response is intended to live for as long as the client stays connected. Note that this design uses one thread per client and therefore does not scale well to large numbers of subscribers.
:- use_module(library(http/sse)).
:- http_handler(root(events), events,
[ spawn([]),
time_limit(infinite)
]).
events(_Request) :-
sse_open,
between(1, infinite, Min),
sse_send(_{event: minute, data: Min}),
sleep(60),
fail.
The library library(http/sse) hides the wire format and
the response headers needed to defeat HTTP intermediaries that buffer
small responses (see sse_open/0 and sse_send/1).
Of course, rather than sleep/1
to decide when to fire the next event this thread typically has to wait
for events in the application. This can be achieved using thread_wait/2
or message queues.