Webhook icon
Schedule icon
WorkingDirectory icon
Commands icon
Docker icon
Script icon
If icon
SlackIncomingWebhook icon
Fail icon
Log icon

Halt a Failing OTA Firmware Rollout at the Canary Cohort

Score OTA canary cohort error and reboot rates against a threshold, alert Slack, and halt a failing firmware rollout before it reaches the fleet.

Categories
Infrastructure

How it works

  1. on_canary_telemetry (io.kestra.plugin.core.trigger.Webhook, keyed with the OTA_CANARY_WEBHOOK_KEY secret) receives the canary cohort metrics from your OTA deploy pipeline as soon as the canary wave finishes. daily_rollout_recheck (io.kestra.plugin.core.trigger.Schedule, cron 0 4 * * *) is the safety net and ships disabled: true until an operator turns it on.
  2. canary_workspace (io.kestra.plugin.core.flow.WorkingDirectory) opens one shared directory so the staged telemetry and the evaluator read the same file.
  3. stage_canary_metrics (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner, image alpine:3.20) writes canary_metrics.json with a heredoc holding a 250 device canary whose reboot failures, error events and unresponsive units breach the default threshold, beside a 4750 device control cohort that stays clean.
  4. evaluate_canary (io.kestra.plugin.scripts.python.Script on python:3.12-slim) prefers the posted webhook body and falls back to the staged telemetry, sums reboot failures, error events and unresponsive devices over the updated count for the canary rate, computes the reboot failure rate and the control baseline, and compares the canary rate against error_threshold_pct. Telemetry that cannot be evaluated defaults to HALT so missing data never widens a rollout. The decision, the rates and the cohort counters are printed as a single ::{"outputs": ...}:: line.
  5. halt_gate (io.kestra.plugin.core.flow.If) branches on halted. A failing canary reaches alert_halt (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) with the rates and the counters, then enforce_halt (io.kestra.plugin.core.flow.If) applies the auto_halt policy with fail_rollout (io.kestra.plugin.core.execution.Fail) or the observe only log_observe_only. A passing canary lands on log_canary_healthy.
  6. The flow level errors handler (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) reports any failure with the execution id, because a gate that dies silently is indistinguishable from a cleared rollout.

What you get

  • A halt decision computed from real cohort telemetry, with the canary rate compared against a single threshold input.
  • Reboot failure rate tracked separately from soft error events, because a device that never reboots never phones home.
  • A control cohort baseline in the same evaluation, so environment wide glitches do not read as firmware failures.
  • A fail versus observe policy in one input, so the same flow stops the release pipeline or reports the verdict.
  • rollout_decision, halted, canary_error_rate, reboot_failure_rate and control_error_rate as typed outputs for release dashboards.

Who it's for

  • Firmware and embedded release engineers rolling OTA updates who need the canary wave gated before the fleet is reached.
  • IoT platform owners who want a bricking class regression to stop the pipeline instead of surfacing as a support spike.
  • Reliability leads standardizing release gates across product lines with one version controlled decision.

Why orchestrate this with Kestra

An OTA pipeline that pushes everywhere at once has no natural pause, and by the time a bad build is obvious the canary advantage is gone. Kestra gives the telemetry a webhook to land on, a shared workspace for the fixture and the evaluator, a branch that separates halt from go, a policy input for enforce versus observe, and outputs the release dashboard can consume. The threshold, the escalation policy and the execution history that proves the gate ran live together, and a schedule can rescore telemetry while a rollout is paused.

Prerequisites

  • A worker with Docker access, the fixture runs in alpine:3.20 and the evaluator in python:3.12-slim.
  • An OTA deploy pipeline that can POST canary cohort telemetry as JSON, or rely on the bundled fixture for trial runs.
  • A Slack incoming webhook for the halt alert and for failure alerts.

Secrets

  • OTA_CANARY_WEBHOOK_KEY: key segment guarding the canary webhook URL, anyone holding it can trigger an evaluation run.
  • SLACK_WEBHOOK_URL: Slack incoming webhook for the halt alert and failure alerts.

Quick start

  1. Add the two secrets to your Kestra namespace.
  2. Run the flow once with the default inputs and confirm rollout_decision reads HALT, canary_error_rate reads 11.79, reboot_failure_rate reads 3.66, control_error_rate reads 0.53, and the Slack alert arrived.
  3. Raise error_threshold_pct to 15 and re-run to watch the same telemetry pass as GO while the rates stay identical.
  4. Re-run with auto_halt set to false and watch log_observe_only keep the execution green while the halt alert still fires.
  5. Point your deploy pipeline at /api/v1/{tenant}/executions/webhook/{namespace}/firmware-ota-canary/{OTA_CANARY_WEBHOOK_KEY} and enable daily_rollout_recheck once the path is trusted.

How to extend

  • Add a second threshold for reboot_failure_rate inside evaluate_canary so a bricking class regression halts even when total error volume stays low.
  • Fetch the live rollout state with an io.kestra.plugin.core.http.Request against your device cloud before evaluating, keeping the staged fixture as the offline fallback.
  • Persist every evaluation with io.kestra.plugin.jdbc.postgresql.Queries to prove canary health across the whole rollout history.
  • Fan out per device model with io.kestra.plugin.core.flow.ForEachItem over a subflow that gates one model cohort each.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.