Zum Inhalt springen
Deutsch

SSE (Server-Sent Events)

SseActor stellt einen Server-Sent-Events-Endpoint bereit. SSE ist ein einseitiges Push-Protokoll vom Server zum Client über einfaches HTTP — einfacher als WebSocket, mit browsernativem Auto-Reconnect über die EventSource-API.

import { ActorSystem, Props, SseActor } from 'actor-ts';
const sse = system.spawn(
Props.create(() => new SseActor({
host: '0.0.0.0',
port: 8080,
path: '/events',
})),
'sse',
);
// Irgendwo in der App — an alle verbundenen Clients pushen:
sse.tell({
kind: 'broadcast',
event: 'order-placed',
data: JSON.stringify({ orderId: 'o-1' }),
});
// An eine bestimmte Verbindung pushen:
sse.tell({
kind: 'send',
connectionId: 'conn-42',
event: 'private',
data: '...',
});

Browser-Clients konsumieren über:

const events = new EventSource('http://my-server/events');
events.addEventListener('order-placed', (e) => {
console.log(JSON.parse(e.data));
});
interface SseActorSettings extends BrokerCommonSettings {
host: string;
port: number;
path?: string; // Default '/events'
keepaliveMs?: number; // Default 30_000 — sendet Kommentare, um Verbindungen am Leben zu halten
}

keepaliveMs steuert, wie oft der Server Kommentar-Frames (: keepalive) sendet, damit zwischengeschaltete Proxies Idle- Verbindungen nicht schließen. 30 Sekunden sind typisch.

SSE hat ein spezifisches Wire-Format:

event: order-placed
data: {"orderId":"o-1"}
id: 42
event: ping
data:

Das Framework baut das für dich:

sse.tell({
kind: 'broadcast',
event: 'order-placed', // Event-Name (Default 'message')
data: JSON.stringify(o), // Payload
id: String(Date.now()), // optional — vom Client für last-event-id-Reconnect genutzt
});

id ist wichtig: Wenn ein Client die Verbindung verliert und wieder aufbaut (der Browser tut das automatisch), schickt er Last-Event-ID — dein Actor kann ab dort wieder aufnehmen.

class SseActor extends Actor<...> {
override onReceive(msg) {
if (msg.kind === 'connection-opened') {
const lastId = msg.lastEventId;
if (lastId) {
// Events neuer als lastId an diesen Client wiedergeben
this.replayFrom(msg.connectionId, lastId);
}
}
}
}

Entscheidend für resumable Streams — ohne das verliert der Client Events während der Trennung. Kombiniert mit einem Event-Store (oder einer Journal-gestützten Projektion) kannst du At-least-once-Push-Zustellung bauen.

Drei primäre Einsatzfälle:

  1. Einseitiges Push vom Server zum Browser — Live-Feeds, Benachrichtigungen, Echtzeit-Dashboards.
  2. Wenn WebSocket Overkill ist — einfacheres Protokoll, einfacheres Debugging (es ist ja nur HTTP).
  3. Freundlich zu HTTP-Infrastruktur — funktioniert durch Proxies, Load-Balancer, CDNs, die kein WS verstehen.

Für bidirektionale Kommunikation nimm WebSocket. Für Request/Response-RPC nimm einfaches HTTP.