The chef-client run & convergence
Compile, converge, idempotency.
A chef-client run has two phases. First compile: Chef evaluates the Ruby of every recipe in the run-list top to bottom and builds an ordered resource collection. Then converge: it walks that collection and, for each resource, checks the current state and takes action only if it differs from desired. Understanding the two phases explains a lot of Chef behavior — especially that all Ruby runs during compile, before any resource converges.
1gather
node data (ohai) + run-list
2compile
evaluate recipes → resource list
3converge
act on resources that differ
4report
update node on the server
Ruby logic runs at compile; resources act at converge. Mixing the two phases is the classic Chef gotcha.
terminal
$ chef-clientSynchronizing Cookbooks: web (1.2.0)Converging 3 resources* package[nginx] action install (up to date)* template[/etc/nginx/nginx.conf] action create- update content in file /etc/nginx/nginx.conf* service[nginx] action reload (skipped due to notifies)Chef Infra Client finished, 1/3 resources updated
Compile time vs converge time trips everyone
All Ruby (variable assignments, conditionals, mysql query at the top of a recipe) executes during compile, before any resource acts — so reading a file a resource creates “above” it returns nothing, because that resource has not converged yet. When you need a value that only exists after a resource runs, use lazy evaluation or notifications, not plain Ruby at compile time.