How to dispatch a Server-Sent Event on receiving data from another worker?

I would like to send a Server-Sent event when data arrives from a Cloudflare queue. I’ve tried using an EventEmitter to trigger the SSE when the exported queue function is called but the runtime scheduler, rather pessimistically IMHO, believes that the script will never generate a response. I’m not sure what the reasoning is… perhaps EventEmitter isn’t supported by the runtime or the scheduler is assuming, despite the ‘text/event-stream’ header in the response, that the script is permanently blocked. Clarification would be appreciated… I’ve probably missed something and VSCode Copilot, though inherently optimistic, currently seems stymied.

A polling approach, via setInterval, would work around this but I would prefer a reactive approach to minimize CPU usage. A queue is nice, but other data transfer mechanisms can be considered. Is there a way to do this which minimizes resource use?

SSE seems preferable to websockets for one-way notifications since it’s simple, widely-adopted in browsers, and http/2 addresses the browser socket shortage in http/1. Perhaps standardization might also make it easier for CDNs to extend event delivery guarantees to browsers. Open to suggestions, though!


sse-proto : the SSE server
sse-client : the SSE client
sse-publish-proto : publishes to the queue

When the sse-proto GET on ‘/events’ is executed, perhaps via the swagger ui, the Cloudflare log contains “The script will never generate a response”.

The Cloudflare docs state that EventEmitter is supported in workers.

If the EventEmitter handler is replaced with a setInterval poll:

		setInterval(() => {
			const msg = 'data: { "info": "some info", "source": "some source" }\n\n';
		}, 5000);		

then it works.

a Durable Object instance can use a global variable to bridge queue and request handlers, though variable contents would be lost in an eviction. It can also expose a websocket or fetch endpoint. The MQTT pub/sub service also seems interesting. There may be other possibilities…

hmm… as stated in the link, values written using the Transactional Storage API are preserved across evictions. This isn’t the whole story, though. Values which serialize to less than 2K bytes can be stored in RAM using the serializeAttachment() call. Doubtless known to seasoned CF devs but perhaps helpful to some.

the GraphQL stitching community is a good source of information for this. An executable placed on a Durable Object can return information to a client through a worker proxy using SSE.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.