StackStorm Sensors: Reliable Event Detection That Survives Restarts
A StackStorm sensor that replays every event after a restart floods your rules. Build cursor persistence, dedup, and missed-event recovery — drafted with AI, tested at the boundaries.
- #automation
- #ai
- #stackstorm
- #event-driven
- #sensor
A StackStorm sensor is the eyes of your event-driven automation: it watches an external source — an API, a queue, a log stream — and emits triggers that fire rules. When the sensor works, the whole pipeline feels effortless. When it fails, it fails at the boundaries, and those boundaries are nasty. The signature failure is a sensor that, after a restart, re-reads its source from the beginning and re-emits every event it has ever seen, firing a flood of duplicate actions. I have watched a sensor restart innocuously during a deploy and, in the space of a minute, re-trigger three weeks of “scale up” actions because it had no memory of what it had already processed.
The steady-state happy path — an event arrives, a trigger fires, a rule runs — is the easy ninety percent. The hard ten percent is startup, restart, and source hiccups, and that’s where sensors must be designed carefully. AI drafts the sensor skeleton readily; the boundary behavior is what you design and test deliberately.
Persist the Cursor, and the Order of Operations
A sensor must remember where it left off, or a restart either replays everything or skips everything. StackStorm gives sensors a datastore for exactly this. The cursor — a timestamp, an offset, a last-seen ID — records the high-water mark of what’s been processed.
class OrderEventSensor(PollingSensor):
def poll(self):
cursor = self._get_datastore_value("last_cursor") or self._initial_cursor()
events = self._source.fetch_since(cursor) # only newer than cursor
for event in events:
if self._already_emitted(event["id"]): # dedup overlapping windows
continue
self.sensor_service.dispatch(
trigger="myorg.order_event",
payload=self._to_payload(event), # stable, minimal, unique-keyed
)
self._mark_emitted(event["id"])
self._set_datastore_value("last_cursor", event["cursor"]) # AFTER dispatch
The order of the last two lines is the whole game. The cursor advances after a successful dispatch, never before. Advance it before dispatch and a crash in the gap skips the event permanently — it’s behind the cursor now, so the next poll never sees it. The dedup check before dispatch handles the opposite hazard: polling windows overlap, sources re-deliver, and without a recently-seen-ID set the sensor double-emits. When a model drafts a sensor, these two lines are what you scrutinize, because the naive draft advances the cursor in the wrong place and omits the dedup entirely.
Recover Missed Events on Startup
A sensor that starts reading from “now” silently drops every event that occurred while it was down. If the sensor was offline for a deploy, an outage, or a crash loop, those events are simply gone — and gone events in an automation pipeline mean actions that should have happened didn’t. The fix is to start from the persisted cursor, not from the present, and reconcile against the source for anything that arrived during downtime.
This is the difference between a sensor that’s merely live and one that’s correct. Starting from the persisted cursor means the first poll after a restart catches up on the backlog the sensor missed, in order, before resuming normal operation. The cost is that the catch-up might be large after a long outage, which is why the dedup and the cursor discipline above matter even more during recovery — you’re replaying a window and must not double-emit.
Prompt: “Design a StackStorm polling sensor for an order-events API that supports cursor-based pagination. Persist the last cursor in the datastore, advancing it only after a successful dispatch. Add a recently-seen-ID dedup set to handle overlapping poll windows. On startup, resume from the persisted cursor to catch events that arrived during downtime. Emit a trigger payload with a stable unique event key. Produce a restart-recovery test plan that asserts no duplicates and no missed events.”
What it returns: a sensor class with cursor-after-dispatch ordering, a dedup set, startup reconciliation, and a restart-recovery test plan. The cursor-advance ordering and the startup-from-cursor behavior are the parts that prevent the two opposite catastrophes, so confirm both are right.
Hand Consumers a Unique Key
A sensor often cannot guarantee exactly-once emission on its own — overlapping windows and at-least-once sources make perfect dedup at the sensor impossible in the general case. The honest design accepts this and compensates by emitting a stable, unique event key in every trigger payload, so the rules that consume it can dedupe too. This is the same idempotency reasoning that runs through reliable automation: when you can’t guarantee single delivery, you make repeated delivery harmless. A rule that keys its action on the event ID is safe even if the sensor double-emits during a recovery window.
Test at the Boundaries, On Purpose
Everything that breaks a sensor lives at the boundaries, and the boundaries don’t occur during a casual happy-path test. So force them. Stop the sensor mid-stream, restart it, and assert two things: no event was emitted twice, and no event in the gap was skipped. Inject a source hiccup — a timeout, an error response — and confirm the sensor backs off and resumes without advancing the cursor past undispatched events. Take the sensor down for a few minutes while events flow, bring it back, and confirm it catches up rather than starting fresh. These three tests cover the failures that actually happen, which the happy path never exercises.
The pattern is consistent with the rest of AI for Automation: the model drafts the sensor, the dedup, and the recovery plan competently, but the load-bearing details — cursor-after-dispatch, startup-from-cursor, and a consumer-usable event key — are the ones you verify, because each one fails at a boundary that only appears when you deliberately create it. For the design checklist see the StackStorm sensor prompt and the StackStorm action pack companion.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.