Skip to content

Event sourcing

kill -9 a jaque engine mid-check and restart it: it comes back with the exact same state it had a moment before, full history included. That’s not a snapshot trick — it’s a consequence of how the whole system is built.

Every fact — a check result arrived, a state transitioned, an ack was set, a downtime was scheduled, a notification was sent — is appended as an event to a log. No component reaches in and flips a status field. “Current state” is a projection: whatever you get by replaying the log from the start (or from the last checkpoint) and folding each event into a running view.

result --> state machine --> event(s) --> event log --> projection --> UI / status.json

The engine that decides state transitions, the UI, the perfdata sinks, and the notifier are all just different folds over the same log, each with its own read position. None of them talk to each other directly.

Why this buys you more than an audit trail

Section titled “Why this buys you more than an audit trail”
  • Crash recovery is free. There is no separate “save state on exit” path to get wrong — a process that dies mid-check loses nothing beyond the in-flight check, because state was never anywhere but the log.
  • History is the same mechanism as current state, not a bolted-on table. ListHistory in the query API and the dashboard’s timeline read the same log a fresh replica would replay from zero.
  • Hot config reload is an event too. ConfigReloaded — and ConfigRejected when the new config fails validation — land in the log like anything else, so “what changed and when” is answerable after the fact, not just observable in a log line that scrolled past.
  • Multiple consumers scale independently. A perfdata sink, a Livestatus reader, and the engine’s own state projection each follow the log at their own pace; a slow one doesn’t block a fast one, it just falls behind (and that lag is a metric you can watch — see Metrics).

The log has three transports, selected with -eventlog: memory (the default — no durability, replay only from process start), file:// (embedded Pebble, durable, no external service — see Single binary), and nats:// (external NATS JetStream, for clustered deployments where more than one process needs to read the same log); see Cluster and coordination.

jaque’s event log is not a metrics time series database, and it does not try to be one. Perfdata — the numeric measurements a check produces — is a separate concern that flows out to a Sink (ClickHouse, remote_write) for whoever already owns that discipline. What the log guarantees is that every decision the engine ever made is reconstructable, not that every number a check ever printed lives there forever (see Archive for the log’s own long-term retention story, which is opt-in and separate from perfdata sinks).