Push-based query
このコンテンツはまだ日本語訳がありません。
The live PersistenceQuery
streams — eventsByPersistenceId and eventsByTag — are
poll-based by default: they re-read the journal every
pollIntervalMs (default 1 s) for new events. Fine for most
projections, but up to a second of latency per event.
When the underlying journal exposes an in-process event bus
(journal.events), those same live streams automatically
switch to push delivery — they subscribe to the bus and yield
each new event within milliseconds, keeping the poll only as a
safety net. There is no opt-in flag; it happens whenever the
journal has a bus.
Which journals push
Section titled “Which journals push”The in-memory and SQLite journals wire up journal.events
automatically, so their live streams push. A journal without a
bus simply polls. A custom Journal opts in by exposing an
events bus and publishing on each successful append.
Consuming a live stream
Section titled “Consuming a live stream”Push applies to the live streams (eventsByTag /
eventsByPersistenceId), which return an AsyncIterable:
import { offsetStart } from 'actor-ts';// `query` is a PersistenceQuery (SqliteQuery / InMemoryQuery / …) — see Persistence query.
for await (const tagged of query.eventsByTag<AccountEvent>('account', offsetStart())) { handle(tagged.event); // delivered by the bus in ~ms when available, // otherwise by the next poll}LiveQueryOptions tunes the fallback poll — { pollIntervalMs }.
There is no push field: push is
automatic when the bus exists, so you can set a higher
pollIntervalMs (the poll is only a backstop).
The bus delivers the event, not just a wake-up
Section titled “The bus delivers the event, not just a wake-up”The push stream subscribes to the bus first, does the catch-up read for history, then drains buffered bus events — so there’s no start-up gap. Each publication carries the event object itself, so the stream yields it directly; it does not re-query the journal on every notification.
At-least-once is preserved: if a subscription misses a publication (start-up race, crash), the fallback poll picks it up.
ProjectionActor polls — it does not use the bus
Section titled “ProjectionActor polls — it does not use the bus”ProjectionActor drives itself by
polling the one-shot currentEventsByTag /
currentEventsByPersistenceId on a timer (pollIntervalMs); it
does not subscribe to the journal bus. So a projection’s
latency is bounded by its poll interval. For true push latency,
consume the live events* stream directly (as above) rather than
going through ProjectionActor.
In-process only
Section titled “In-process only”journal.events is an in-process bus — push works only when the
writer and the stream consumer share an ActorSystem (same
node). Across nodes you’re bounded by polling, by the journal’s
own replication / CDC, or by publishing on
DistributedPubSub yourself.
Where to next
Section titled “Where to next”- Persistence query — the underlying
events*API. - Projections — the poll-based projection actor.
- DistributedPubSub — cross-node real-time fan-out.
