Kepler.Poller (Kepler v0.1.0)

Copy Markdown View Source

The single process that turns counters into conditions.

This is the architectural trick, and it is the whole reason Kepler is cheap enough to leave on: event volume and evaluation volume are decoupled. Telemetry handlers increment counters and nothing else, however many events arrive. Once per tick, this process reads every counter, samples every declared gauge, and evaluates every condition in one pass.

A hundred thousand events per second costs a hundred thousand atomic increments plus one pass per second. Adding a watch adds work to the pass, not to your request path.

What one tick does

  1. Read every telemetry counter and difference it against the last read.
  2. Sample tier 2 sources, one call per process and one per VM group.
  3. Evaluate conditions in dependency order, so a composite condition sees current-tick results from everything it reads.
  4. Advance each watch's Kepler.Trigger, applying sustained: and cooldown:.
  5. Hand any resulting events to Kepler.Emitter and record what the pass cost in Kepler.Budget.

A source with nothing to report yields :no_data, and a watch with no data is not evaluated at all — its trigger holds. That is deliberate: feeding a condition a zero it did not observe is how a quiet period turns into a false resolution.

Summary

Functions

Returns a specification to start this module under a supervisor.

Reports a discrete occurrence — a system monitor trip, a crash report.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

occurred(name, reading)

@spec occurred(atom(), map()) :: :ok

Reports a discrete occurrence — a system monitor trip, a crash report.

Discrete sources bypass the counter path entirely: there is no number to fold and nothing to wait for a tick to notice. They still go through the same cooldown: gate and the same bounded, non-blocking egress as everything else.