Skip to main content
RunBook Academy

AnsibleXXXIX · Automation Platforms, RBAC and Event-DrivenAutomation platforms, RBAC and event-driven automation

Automated response without automating the outage

Advanced⏱ ~30 min

What you'll learn

  • Trace the amplification loop from an action back to its own trigger
  • Apply throttle and lock correctly, and state what each does not do
  • Cap the blast radius of a single firing rather than of a single run
  • Decide when the correct automated response is to page a human

Prerequisites

Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11

Not yet marked complete on this device.

Start with the incident, because the controls only make sense once you have seen what they are for.

A shared database becomes slow at 02:12. Application servers start failing their health checks. The monitoring system fires ServiceUnhealthy for each of them. A rulebook responds by restarting the service on the affected host.

The restarted service reconnects, hammers the already-slow database harder than a warm one would, fails its next health check, and fires the alert again. Meanwhile eleven other hosts are doing the same.

By 02:22 the rulebook has performed four hundred restarts. The database is now unusable, because four hundred connection storms arrived while it was struggling.

The incident lasted ten minutes and the automation caused nine of them.

Every element of that is ordinary. The alert was correct: the service was unhealthy. The remediation was reasonable: restarting a hung service is what an operator would have done. The rulebook worked exactly as designed.

What was missing was any recognition that the action feeds the source.

The amplification loop

Draw the model from the previous lesson again, and then draw the arrow nobody draws:

    +----------------------------------------------+
    |                                              |
    v                                              |
 [ source ] --> [ condition ] --> [ action ] ------+
   alert           matches         restarts
   fires                           the service

The feedback arrow is the one that turns a rule into a loop. It is invisible in a linear description — “when the service is unhealthy, restart it” contains no hint of it — and it is present far more often than teams expect, because most remediations touch the thing being monitored. That is what makes them remediations.

Rate limiting: throttle

The rulebook mechanism for event storms is the throttle node on a rule. The upstream documentation states the problem it exists for:

“When we have too many events within a short time span (event storm) and the condition matches, we would trigger the action multiple times within that time period.”

Three variants, and they are genuinely different:

once_within — react immediately, then go quiet.

throttle:
  once_within: 5 minutes
  group_by_attributes:
    - event.meta.hosts
    - event.code

“When the condition matches for the first time we trigger the action and then suppress further action till the time window expires.” This is the one you want for remediation: respond fast, do not respond again while the first response is still settling.

once_after — wait, then react once for everything.

throttle:
  once_after: 5 minutes
  group_by_attributes:
    - event.meta.hosts
    - event.code

Collect the unique events until the window expires, then act once. Good for summarising and notifying; bad for anything time-critical, because you have deliberately added five minutes of delay.

accumulate_within — react only if it happens enough.

throttle:
  accumulate_within: 5 minutes
  threshold: 10
  group_by_attributes:
    - event.meta.hosts
    - event.code

Fire when the count reaches the threshold inside the window. This is a noise filter: it distinguishes one flap from a real pattern.

Serialisation: lock

lock is a different control and the two get confused constantly.

The documentation: “An optional string based lock ensures sequential execution of this action when execution strategy is set to parallel. It can also be a string field from the event payload. The locks are per ruleset, if a lock is in place all actions that use the same lock will wait till the earlier action has completed.”

action:
  run_job_template:
    name: Fix My Datacenter
    organization: Default
    lock: "{{ event.datacenter }}"

Capping the blast radius of a firing

Everything this course teaches about blast radius applies to the playbook an event triggers. --limit, serial, max_fail_percentage, preconditions — all of it, unchanged.

There is one addition that is specific to event-driven automation, and it is the control most often missing:

A cap on how many hosts a single firing may change, enforced inside the playbook, independent of what the event said.

The reasoning: the event payload determines the target. The payload comes from a system you do not control, over a transport that can be wrong, duplicated or malicious. A rule that targets whatever the event names has delegated its hosts: line to the monitoring system.

- name: Event-triggered remediation
  hosts: "{{ target_hosts }}"
  gather_facts: false
  any_errors_fatal: true
  tasks:
    - name: Refuse to remediate more than the permitted number of hosts
      ansible.builtin.assert:
        that:
          - ansible_play_hosts_all | length <= 3
        fail_msg: >-
          Refusing: this remediation is capped at 3 hosts and the event
          resolved to {{ ansible_play_hosts_all | length }}. A fleet-wide
          symptom is an incident, not a remediation - page instead.
      run_once: true
      tags: [always]

This is the guardrail pattern from Part XXIV, and the fail_msg carries the actual argument: if the symptom is fleet-wide, the cause is probably shared, and the response should be a human rather than a hundred restarts.

The kill switch

Every automated response needs a way to be stopped by a human under pressure, and there are three properties that matter.

Fast. Seconds. If it requires a merge request, it is not a kill switch.

Reachable. By whoever is on call at 03:00, without a laptop, without a VPN they may not be able to reach, and without the permissions of the person who built the rulebook.

Verifiable. The person who pulls it can confirm within seconds that it took effect. “I disabled it, I think” is not an incident-management state anybody should be in.

Practical implementations, from coarse to fine:

MechanismSpeedGranularityNote
Stop the rulebook processImmediateEverythingThe blunt instrument. Make sure the supervisor does not restart it
shutdown action on a control eventSecondsEverything in that rulesetA kill switch expressible in the rulebook itself
Disable the job template the rule triggersSecondsOne responsePlatform-side, leaves the rulebook running and failing loudly
A precondition on a flag the play readsOne runOne responseWorks with no platform. The flag must live where a responder can change it in seconds

Approval above a threshold

The bridge between fully automated and fully manual is the approval node from lesson 5, applied by blast radius:

Blast radius of the responseControl
Read-only — diagnostics, ticket, notificationFully automatic
One host, reversible, service-levelAutomatic with throttle, lock and a cap
Several hosts, or irreversible on oneApproval node, with the diagnostics already gathered
Fleet-wide, or data-affectingPage a human. No automated path exists

The middle row is where the design effort pays off. A workflow that runs diagnostics automatically and then waits for approval before changing anything gives the responder the thing they actually want at 03:00 — evidence, already collected — without giving the rule the authority to act on it.

That arrangement is often better than either extreme. It is faster than a human doing the diagnosis, and safer than a rule doing the remediation.

Knowledge check

Knowledge check · 5 questions

  1. Q1. A rulebook restarts a service when its health check fails. During a shared-database slowdown it performs four hundred restarts in ten minutes across twelve hosts. What is the structural defect?

  2. Q2. Which statements about throttle and lock are accurate? Select all that apply.

  3. Q3. A cooldown of five minutes after each remediation is sufficient protection against a service that flaps every six minutes.

  4. Q4. You add an assertion to an event-triggered playbook refusing to run when the event resolves to more than three hosts. What is the best justification for this cap?

  5. Q5. A kill switch that has never been tested should be treated as a plan rather than as a control.

Passing score: 75%. Answers are checked in this browser.