SLO and error-budget gates
Stop eyeballing a Grafana panel before every release. Compute availability from logs, compare it to the SLO, and let an OrchStep workflow promote or freeze the release on the error budget.
blog/slo-gatesYou have an SLO. You have a dashboard. What you don't have is a release process that reads the dashboard. So before each deploy someone squints at a Grafana panel, says "looks fine," and ships — and the error budget is a number nobody consults until it's already gone.
The fix isn't another dashboard. It's making the error budget a step in the release path: compute availability from the logs, compare it to the target, and branch. If the budget can absorb the risk, promote. If it can't, freeze. This post wires that gate as an OrchStep workflow you can call from CI before any deploy.
The gate
Three moves: count the requests and errors, compute availability, then an if: that promotes or freezes. The decision is data, not a vibe.
name: slo
# Compute availability from request logs, compare against the SLO target,
# and gate the release: promote only when the error budget can absorb it.
defaults:
service: checkout
target_pct: "99"
tasks:
# `orchstep run gate --var service=checkout`
gate:
steps:
- name: count
func: shell
do: echo "scanning {{ vars.service }} request logs for the trailing 30 days"
outputs:
total: "1000000"
errors: "4000"
- name: availability
func: shell
do: echo "{{ vars.service }} availability computed from logs"
outputs:
pct: "99"
- name: decide
if: '{{ ge (atoi steps.availability.pct) (atoi vars.target_pct) }}'
then:
- name: promote
func: shell
do: echo "{{ vars.service }} within SLO ({{ steps.availability.pct }}% >= {{ vars.target_pct }}%) — promoting release"
else:
- name: freeze
func: shell
do: echo "{{ vars.service }} error budget exhausted ({{ steps.availability.pct }}% < {{ vars.target_pct }}%) — freezing releases"
finally:
- name: record
func: shell
do: echo "SLO decision for {{ vars.service }} recorded in the error-budget ledger"The demo emits a literal pct so it runs anywhere. In production, the count step shells out to your log query (Loki, CloudWatch Insights, BigQuery — whatever holds the request log), and availability does the arithmetic. The branching logic above never changes.
The branch is the point
A bare threshold check exits non-zero and stops. That's fine for a single answer, but a release gate needs two distinct actions — promote vs. freeze — plus a record that always runs regardless of which way it went. That's exactly the if: / then: / else: / finally: shape:
then:runs the promote path when availability clears the target.else:runs the freeze path when the budget is spent.finally:writes the decision to the ledger either way, so you have an audit trail of every gate, not just the failures.
Wire orchstep run gate as a required step in your deploy pipeline and the budget stops being advisory. A frozen release is a non-zero exit the pipeline already knows how to honor.
See which branch fires — before you ship
The most useful thing here is reading the decision before it executes. A dry run resolves the variables, evaluates the if:, and shows you the path the real run will take:
orchstep run gate --var service=checkout --var target_pct=100 --dry-runBump target_pct to 100 and the dry run shows the freeze branch lighting up — proof the gate actually holds, without freezing anything. Details: Previewing with Dry Run and Conditionals & Branching.
What you gained
| Concern | eyeball the dashboard | OrchStep gate |
|---|---|---|
| Who reads the budget | a human, before deploy | a step, every deploy |
| Promote vs. freeze | a judgment call | an if: on real numbers |
| Audit trail | none | finally: writes every decision |
| Per-service targets | a mental note | --var target_pct= |
If your release cadence is slow enough that a human truly does check the budget every time, you may not need this. The moment deploys outpace attention, make the budget a gate.
Where to go next
- Conditionals & Branching —
if:/then:/elif:/else: - Variables & Outputs — capturing numbers as step
outputs: - Error Handling —
finally:and guaranteed steps
Got an SLO nobody checks before shipping? Make the error budget a step the deploy can't skip.
curl -fsSL https://orchstep.dev/install.sh | sh