Skip to main content
RunBook Academy

AnsibleVI · Configuration and PrecedenceConfiguration and precedence

Forks, timeouts and what they cost

Intermediate⏱ ~17 minansible-core

What you'll learn

  • State what forks and timeout actually control, and their built-in defaults
  • Treat simultaneous host count as a blast-radius decision rather than a tuning knob
  • Explain what a raised connection timeout hides and what it costs in wall-clock time
  • Distinguish the timeout configuration setting from the timeout task keyword

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.

Two settings decide how a run behaves at scale, and both ship with values chosen for a laptop talking to a handful of machines.

Read-only / Safethe two numbers
$ ansible-config dump | grep -E '^(DEFAULT_FORKS|DEFAULT_TIMEOUT)'
DEFAULT_FORKS(default) = 5
DEFAULT_TIMEOUT(default) = 10

Neither is right for a fleet. Neither is safe to change without understanding what it was doing for you.

forks: how many hosts at once

forks is the maximum number of worker processes the controller runs in parallel. Under the default linear strategy, Ansible executes one task across all targeted hosts before moving to the next task, and forks caps how many of those hosts are worked on simultaneously.

For 300 hosts at forks = 5, each task proceeds in 60 sequential batches of 5. If a task takes two seconds, that task alone takes two minutes. Multiply by the number of tasks in the play and the arithmetic explains most complaints about Ansible being slow.

Configured in [defaults], overridable per run:

[defaults]
forks = 20
Read-only / Safethe three ways to set it
ansible-playbook site.yml --check -f 20
ANSIBLE_FORKS=20 ansible-playbook site.yml --check
# or forks = 20 in the [defaults] section of ansible.cfg

The framing that matters

The obvious reading of forks is “how fast”. The reading this course insists on is how many machines are in a broken state at the same moment.

A play that reconfigures a service is, for a few seconds per host, a play that has stopped that service. At forks = 5, five hosts are in that state at once, and a task that turns out to be wrong affects five machines before anybody can interrupt it. At forks = 100, a hundred are.

forks = 5 is therefore an accidental safety limit. It is not a good one — it is unrelated to your service, your redundancy, or your capacity — but it is a limit, and raising it removes protection you were relying on without knowing it.

What raising forks costs the controller

Every fork is a real process. On the controller, per host being worked on, you pay for:

  • a Python process, with the Ansible libraries loaded;
  • an SSH connection, plus a persistent control socket if ControlPersist is in use — the default ssh_args is -C -o ControlMaster=auto -o ControlPersist=60s;
  • file descriptors for that connection and its control path;
  • memory to hold the module payload and the result, which for a task returning large output is not small.

The controller is therefore the constraint, not the fleet. A forks value that a 32 GiB controller handles comfortably will make a 2 GiB one swap, and a swapping controller produces timeouts that look exactly like network faults on the managed nodes.

timeout: how long to wait for a connection

timeout is the connection timeout used by connection plugins, default 10 seconds. It is how long Ansible waits to establish a connection to a managed node before declaring it unreachable.

It is not a task timeout, and the name collision is a genuine trap — covered below.

What a raised timeout hides

The tempting fix for “some hosts intermittently fail as unreachable” is to raise timeout to 30 or 60. It works, in the sense that the failures stop.

Consider what it means for a host to need 45 seconds to accept an SSH connection. Something is wrong with that machine: it is under memory pressure, its disk is saturated, sshd is struggling, or the path to it is degraded. At timeout = 10 you learn this immediately, in the form of a clear unreachable result. At timeout = 60 the run succeeds and you learn nothing — and the sick host is now receiving configuration changes while it is sick.

A raised timeout converts a fast, accurate failure into a slow, misleading success. That is a bad trade in the direction that matters.

What a raised timeout costs in wall-clock

The two settings interact, and the interaction shows up on the worst day.

An unreachable host occupies a fork for the whole timeout period. With forks = 5 and timeout = 60, fifty dead hosts occupy the controller for ten batches of sixty seconds — ten minutes before any healthy host is touched. With timeout = 10 the same fifty cost about one hundred seconds.

During an incident, when unreachable hosts are exactly what you have, a generous timeout turns your diagnostic run into something you sit and watch.

Knowledge check

Knowledge check · 4 questions

  1. Q1. Why does this course describe raising forks from 5 to 50 as a safety change rather than a performance change?

  2. Q2. A team raises timeout from 10 to 60 because some hosts intermittently report unreachable. What have they actually done? Select all that apply.

  3. Q3. Setting timeout = 600 in ansible.cfg will stop a task that hangs for twenty minutes running a slow command.

  4. Q4. A play sets serial: 4 and the controller config sets forks = 20. How many hosts are worked on in parallel?

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