The facts part of this course covers configuring a persistent cache and
watching it work. This lesson is the performance-engineering view: where
caching belongs in the sequence of changes, and why it is the only lever in
this part whose failure mode is a wrong answer rather than a slow run.
Everything else here fails visibly. A saturated controller reports
unreachable hosts. A free strategy produces a confusing transcript. A
pipelining prerequisite that is not met produces sudo errors. Caching
fails by succeeding — quickly, confidently, with a value that stopped being
true two days ago.
Cache last
The order matters and it is routinely inverted, because caching is the
change that sounds most like a performance feature.
Profile. Confirm gathering is the largest line.
Restrict gather_subset to what the audit proved you read.
Set gathering = smart if the playbook has multiple plays over
overlapping hosts — this gathers once per host per run, with no
staleness risk at all, because the facts are from this run.
Then, if gathering is still a significant cost across separate runs,
cache.
Steps 2 and 3 remove work without introducing any claim about the past.
Step 4 introduces one. Doing step 4 first means you are persisting facts
you did not need to collect, and paying the staleness risk for the
privilege.
Which plugins exist
Read-only / Safecache plugins in ansible-core— A virtualenv with ansible-core 2.21.3 and no collections. This is the complete list core ships.
$ ansible-doc -t cache -l
ansible.builtin.jsonfile JSON formatted files
ansible.builtin.memory RAM backed, non persistent
Two. memory is the default and is not a cache in any useful sense — it
lives for the duration of one run and is discarded. jsonfile writes one
JSON file per host to a directory you choose, and is the only persistent
option in core.
Everything else is in a collection, and this matters when you are pinning
dependencies:
redis is the usual choice where several controllers or CI runners share a
cache, because jsonfile on a local directory gives each of them a
separate, independently stale copy. That is a real operational difference:
with jsonfile, a fact refreshed by your laptop run is not refreshed for
the CI runner, so the same playbook can make different decisions depending
on where it ran.
The configuration keys are worth knowing under their real names, because
the setting name and the ini key differ:
Read-only / Safethe settings and their ini keys— From ansible-config on 2.21.3. Note the ini keys are the fact_caching_* family, which is what you will find in existing config files.
$ ansible-config list | grep -A10 '^CACHE_PLUGIN'
CACHE_PLUGIN: ini key: fact_caching default: memory
CACHE_PLUGIN_CONNECTION: ini key: fact_caching_connection default: null
CACHE_PLUGIN_PREFIX: ini key: fact_caching_prefix default: ansible_facts
CACHE_PLUGIN_TIMEOUT: ini key: fact_caching_timeout default: 86400
The default timeout is 86400 seconds — 24 hours. That is the number a
cache runs with if nobody chose one, and it is far too long for several
facts people routinely branch on.
--flush-cache and who is responsible for it
Read-only / Safethe flag, from the CLI help— ansible-playbook --help on 2.21.3. Read the scope carefully.
$ ansible-playbook --help | grep -A1 flush-cache
--flush-cache clear the fact cache for every host in inventory
Every host in inventory, not the hosts your --limit selects. That is
usually what you want and it is worth knowing before you run it during an
incident on a 2,000-host inventory — the next run for every one of those
hosts pays full gathering price.
The operationally important point is not the flag. It is that cache
invalidation is a responsibility somebody has to own, and Ansible does
not own it. A cache entry expires on a timer; it does not expire because
the host changed.
So the flush has to be wired into the workflows that change the things you
cache:
Configuration changeinvalidate at the point of change— Changes the controller cache, not any managed node. Wire it into the workflows that resize, rebuild or re-image hosts.
# After any workflow that changes hardware, addressing or OS version:
# - VM resize (CPU or memory)
# - re-image / rebuild
# - network reconfiguration or IP change
# - distribution upgrade
ansible-playbook -i inventory/production resize.yml --limit web7
ansible-playbook -i inventory/production site.yml --flush-cache --limit web7
If the resize workflow is a different team’s pipeline, then the flush is a
cross-team dependency, and it needs to be written down somewhere other than
in one person’s memory. This is the part that makes fact caching an
operational commitment rather than a configuration setting.
Deciding what is safe, by rate of change
The useful question is not “should we cache facts”. It is “how fast does
each fact I depend on change, relative to my cache timeout”.
Fact
Changes when
Cacheable for 24h?
ansible_distribution, ansible_os_family
a distribution upgrade
yes
ansible_architecture, ansible_machine
never, in practice
yes
ansible_pkg_mgr, ansible_service_mgr
a major OS change
yes
ansible_memtotal_mb, ansible_processor_count
a VM resize
no if you size anything from it
ansible_default_ipv4, ansible_all_ipv4_addresses
re-addressing, failover, a new interface
no if you template it into config
ansible_mounts, ansible_devices
a disk added, a mount changed
no
ansible_date_time
continuously
never useful from cache
The pattern in the right-hand column: facts that describe the shape of
the machine are safe; facts that describe its current capacity or
addressing are not — because those are exactly the ones that change as a
result of the operational work you do, and exactly the ones that get
templated into configuration.
Configuration changea timeout chosen from the table, with the reason recorded— Controller configuration. It changes how your runs make decisions, which is why the comment is not optional.
[defaults]
gathering = smart
fact_caching = ansible.builtin.jsonfile
fact_caching_connection = /var/lib/ansible/facts
# 4 hours, not the 86400s default. We branch on ansible_default_ipv4 in
# the proxy templates, and failover can re-address a host within a day.
# Any workflow that resizes or re-images MUST run with --flush-cache;
# see RUNBOOK-CACHE-INVALIDATION.
fact_caching_timeout = 14400
Knowledge check
Knowledge check · 4 questions
Q1. Which cache plugins ship in ansible-core?
Q2. Twelve VMs are resized from 8 GiB to 32 GiB. The next run renders a heap size from a cached ansible_memtotal_mb, writes the file, restarts the service and reports changed. What kind of defect is this?
Q3. Which statements about --flush-cache and cache invalidation are correct? Select all that apply.
Q4. gathering = smart reduces fact gathering within a single run and introduces no staleness risk at all.
Passing score: 75%. Answers are checked in this browser.