Windows & aggregations
You will build: a streaming stage that counts and profiles events per key in a sliding window — the primitive behind fraud velocity, fleet health and live dashboards.
Prerequisites
- Comfortable with pulse.yaml anatomy.
1 · Scaffold with a streaming stage
pulse new velocity --source webhook --stage streaming:window5
2 · Declare the window
stages:
- name: window5
engine: streaming
operators:
- { type: keyBy, field: user_id }
- type: window
spec: "sliding(5m,1m)"
aggregations:
events: "count()"
total: "sum(amount)"
big_ones: "countWhere(amount > 100)"
spread: "stddev(amount)"
Two operators: keyBy gives every user_id its own independent window, then window declares the shape. Window specs: tumbling(60s) · sliding(60s,10s) · session(30s) · count(100) · count_sliding(100,10) · global(). The aggregator palette: count() · sum · min · max · avg · first · last · stddev · countWhere(expr) · sumWhere(expr). Both the spec and every aggregation are validated at deploy time — a typo is a named error, not a silent no-op.
3 · Deploy and send a burst
pulse secret set PULSE_WEBHOOK_SECRET dev-secret # the scaffolded webhook source requires it
pulse deploy .
for i in 1 2 3 4 5; do
pulse events publish --topic velocity.in --value '{"user_id":"u1","amount":'"$((i*40))"'}'
done
4 · Watch the aggregates
pulse events tail --topic velocity.window5.out
Aggregate events for key u1: events climbing 1→5, total accumulating, big_ones counting the >100 sends, spread (stddev) widening as amounts diverge.
5 · Prove the isolation
pulse events publish --topic velocity.in --value '{"user_id":"u2","amount":10}'
u2 starts its own window at 1 event — u1's numbers are untouched. Keyed state is per key, always.
What just happened
You declared stateful stream processing without writing state code. The engine maintains per-key windows, applies event-time semantics with watermarks (late events don't silently corrupt the window — genuinely late ones route to a dead-letter queue), and emits aggregate events downstream like any other event. Chain a rule-based stage after this and you have a detector.
Troubleshooting
No aggregate output appears
Check the stage name in your tail command matches the YAML (velocity.window5.out). Aggregates emit as the window updates — send more than one event.
Deploy rejects my window spec
The window/aggregation spec is validated at deploy time — the error names the field. Check the aggregator spelling against the palette in step 2.