Rebuilds an Elasticsearch projection by creating a new versioned index, replaying all events, atomically swapping the alias, and cleaning up the old index — without any search downtime.
Usage
mix orkestra.projection.es.rebuild MyApp.OrderESProjectorOptions
--yes- Skip confirmation prompt (for scripting/CI).
Rebuild sequence
- Validate that the module is an ES projector (
backend: :elasticsearch). - Build a stream of
Snap.Bulk.Action.Indexstructs by replaying all events from the EventStore through the projector's__handle_es__/3. - Call
Snap.Indexes.hotswap/5which atomically creates a versioned index, bulk-loads the stream, refreshes, swaps the alias, and cleans up old indexes (keeping the 2 most recent). - Pause the live GenServer via
GenServer.call(pid, :pause_writes)to prevent race conditions during the alias swap window (RBLD-03). - Reset the Postgres checkpoint so the GenServer replays from position 0.
- Resume the live GenServer via
GenServer.call(pid, :resume_writes).
After resume, the GenServer resubscribes from position -1 (no checkpoint)
and replays all events into the new index. Documents are idempotent
(deterministic _id), so duplicate writes are safe.
Error handling
If hotswap/5 fails (e.g. bulk error, connection failure), the task
exits with an error. The old index and alias remain untouched — no
data loss. Re-running the task starts a fresh rebuild.