Push-basierte Query
Die Live-PersistenceQuery-Streams
— eventsByPersistenceId und eventsByTag — sind standardmäßig
poll-basiert: sie lesen das Journal alle pollIntervalMs
(Default 1 s) auf neue Events erneut. Für die meisten
Projektionen okay, aber bis zu eine Sekunde Latenz pro Event.
Wenn das zugrunde liegende Journal einen In-Process-Event-Bus
(journal.events) bereitstellt, wechseln dieselben Live-Streams
automatisch zu Push-Delivery — sie abonnieren den Bus und
liefern jedes neue Event innerhalb von Millisekunden, wobei das
Polling nur als Sicherheitsnetz bleibt. Es gibt kein
Opt-in-Flag; es passiert, sobald das Journal einen Bus hat.
Welche Journals pushen
Abschnitt betitelt „Welche Journals pushen“Das In-Memory- und das SQLite-Journal verdrahten journal.events
automatisch, ihre Live-Streams pushen also. Ein Journal ohne Bus
pollt einfach. Ein eigenes Journal macht mit, indem es einen
events-Bus bereitstellt und bei jedem erfolgreichen Append
publiziert.
Einen Live-Stream konsumieren
Abschnitt betitelt „Einen Live-Stream konsumieren“Push gilt für die Live-Streams (eventsByTag /
eventsByPersistenceId), die ein AsyncIterable zurückgeben:
import { offsetStart } from 'actor-ts';// `query` ist eine PersistenceQuery (SqliteQuery / InMemoryQuery / …) — siehe Persistence Query.
for await (const tagged of query.eventsByTag<AccountEvent>('account', offsetStart())) { handle(tagged.event); // via Bus in ~ms geliefert, wenn verfügbar, // sonst beim nächsten Poll}LiveQueryOptions justiert das Fallback-Polling — { pollIntervalMs }.
Es gibt kein push-Feld: Push ist
automatisch, wenn der Bus existiert, du kannst also ein höheres
pollIntervalMs setzen (das Polling ist nur ein Backstop).
Der Bus liefert das Event, nicht nur einen Weckruf
Abschnitt betitelt „Der Bus liefert das Event, nicht nur einen Weckruf“Der Push-Stream abonniert den Bus zuerst, macht dann den Catch-up-Read für die Historie und drainiert danach gepufferte Bus-Events — es gibt also keine Startup-Lücke. Jede Publikation trägt das Event-Objekt selbst, der Stream yieldet es also direkt; er fragt das Journal nicht bei jeder Benachrichtigung neu ab.
At-least-once bleibt erhalten: verpasst ein Abonnement eine Publikation (Startup-Race, Crash), holt das Fallback-Polling sie nach.
ProjectionActor pollt — er nutzt den Bus nicht
Abschnitt betitelt „ProjectionActor pollt — er nutzt den Bus nicht“ProjectionActor treibt sich
selbst durch Polling der einmaligen currentEventsByTag /
currentEventsByPersistenceId auf einem Timer (pollIntervalMs);
er abonniert den Journal-Bus nicht. Die Latenz einer
Projektion ist also durch ihr Poll-Intervall begrenzt. Für echte
Push-Latenz konsumiere den Live-events*-Stream direkt (wie oben)
statt über den ProjectionActor zu gehen.
Nur In-Process
Abschnitt betitelt „Nur In-Process“journal.events ist ein In-Process-Bus — Push funktioniert nur,
wenn Writer und Stream-Consumer ein ActorSystem teilen (selber
Knoten). Über Knoten hinweg bist du durch Polling begrenzt, durch
die Replikation / CDC des Journals, oder indem du selbst auf
DistributedPubSub publizierst.
Wie geht es weiter
Abschnitt betitelt „Wie geht es weiter“- Persistence Query — die zugrunde liegende
events*-API. - Projektionen — der poll-basierte Projektions-Actor.
- DistributedPubSub — knotenübergreifender Echtzeit-Fan-out.
