The bounded queue between a firing watch and the outside world.
Firing must never block evaluation, and a wedged endpoint must never become a
memory leak. So the poller casts an event here and moves on; this process
holds a fixed-size queue and runs a bounded number of deliveries at a time,
under Kepler's own task supervisor.
When the queue is full, events are dropped and counted. That is the whole
policy. There is no retry and no durable spool: a delivery lost to a crash is
gone, and Kepler.status/0 will tell you how many. Anything else means
either unbounded growth or retrying into a cluster that is already having a
bad day.
Fan-out
An event routed to several sinks is delivered to all of them concurrently, and each delivery is isolated from the others. A sink that raises, exits, or wedges cannot stop its siblings receiving the same event — it is recorded as that sink's failure and the rest carry on.
Two bounds apply, and they compose:
:max_in_flightcaps how many events are being delivered at once.- A wedged sink is killed after
:delivery_timeout, so it cannot hold an in-flight slot forever behind an endpoint that accepted the connection and then stopped talking.
So the ceiling on concurrent outbound requests is max_in_flight times the
number of sinks a watch routes to — a small, static number, since sinks are
configured rather than discovered.
Telemetry
Kepler emits its own events, so you can watch the watcher:
[:kepler, :delivery, :stop]—%{duration: native}, with:watch,:sink,:module, and:resultin metadata.[:kepler, :delivery, :exception]— a sink that raised, exited, or timed out.%{count: 1}, with:watch,:sink, and:reason.[:kepler, :event, :dropped]—%{count: 1}, with:watch,:severity, and:reason(:queue_full).
Summary
Functions
Returns a specification to start this module under a supervisor.
Queues event for delivery.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec emit(Kepler.Event.t(), :all | [atom()]) :: :ok
Queues event for delivery.
A cast, so it never blocks the caller — the poller is the only producer and it produces at most one event per watch per tick, which is why an unbounded mailbox is not a risk here. The bound that matters is the delivery queue, which this process enforces.