Skip to content

Instantly share code, notes, and snippets.

@bouroo
Last active May 12, 2025 03:52
Show Gist options
  • Save bouroo/4b91e535a7f036cb8ab2ba4cb16ae88e to your computer and use it in GitHub Desktop.
Save bouroo/4b91e535a7f036cb8ab2ba4cb16ae88e to your computer and use it in GitHub Desktop.
example for cloudflare worker server-sent events
/**
* Cloudflare Worker for Server-Sent Events (SSE)
*
* This worker demonstrates how to set up an SSE endpoint
* that sends an initial message and then periodic updates.
*/
// Listen for incoming requests
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
/**
* Handles incoming requests and initiates the SSE stream.
* @param {Request} request The incoming request.
* @returns {Response} The SSE response.
*/
async function handleRequest(request) {
// Create a stream to write the SSE messages.
// TransformStream acts as a buffer between the writer and the reader.
const { readable, writable } = new TransformStream();
// Set necessary headers for SSE and CORS.
const headers = new Headers({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache', // Important for SSE to prevent buffering
'Connection': 'keep-alive', // Keep the connection open
'Access-Control-Allow-Origin': '*', // Allow requests from any origin
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
});
// Asynchronously write messages to the stream.
// We don't wait for this to complete, allowing the Response to be returned immediately
// with the readable stream connected to the writable stream.
streamSSEMessages(writable).catch(console.error); // Log potential errors during streaming
// Return the response with the readable stream attached.
// The client will receive data as it's written to the writable stream.
return new Response(readable, { headers });
}
/**
* Writes Server-Sent Events (SSE) messages to the provided WritableStream.
* @param {WritableStream} writable The stream to write messages to.
*/
async function streamSSEMessages(writable) {
const writer = writable.getWriter();
const encoder = new TextEncoder(); // Reuse TextEncoder for efficiency
let count = 0;
const intervalDuration = 5000; // 5 seconds between messages
/**
* Helper function to format and write a single SSE message block.
* @param {string|number} id The event ID.
* @param {string} [eventType] The event type (optional).
* @param {any} data The data payload (will be JSON stringified).
*/
const writeSSE = async (id, eventType, data) => {
let message = `id: ${id}\n`;
if (eventType) {
message += `event: ${eventType}\n`;
}
message += `data: ${JSON.stringify(data)}\n\n`; // Data field followed by double newline
await writer.write(encoder.encode(message));
};
// Send the initial connection message.
const initialData = { status: true, text: "Hello to SSE message", time: new Date().toISOString() };
await writeSSE(`id-${++count}`, "userConnected", initialData);
// Set up an interval to send periodic messages.
const intervalId = setInterval(async () => {
const periodicData = { status: true, text: `Repeat message: ${count + 1}`, time: new Date().toISOString() };
// Use a try-catch inside the interval to handle potential errors during writing
// without stopping the interval immediately (though stream closure handles cleanup).
try {
await writeSSE(`id-${++count}`, "userMessage", periodicData);
} catch (error) {
console.error("Error writing to stream in interval:", error);
// The stream should ideally close on error, triggering the writable.closed handler.
}
}, intervalDuration);
// Clean up the interval and release the writer lock when the stream closes
// (e.g., client disconnects).
writable.closed
.then(() => {
clearInterval(intervalId);
writer.releaseLock(); // Release the lock acquired by getWriter()
console.log("SSE stream closed and interval cleared.");
})
.catch(err => {
console.error("SSE stream closed with error:", err);
clearInterval(intervalId);
writer.releaseLock(); // Ensure lock is released even if stream closes with error
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment