Skip to content

Commit 6446d3c

Browse files
committed
pgaftest/docs: regression spec + docs for report/advance, no-autopilot, fsm step
Add fsm_step_report_advance.pgaf: a live spec proving the report/advance split works end to end using a no-autopilot node, registered in the default schedule and the node.sch CI schedule. Document the three new pieces of tooling this branch introduces: - the no-autopilot cluster node modifier - the pgaftest "fsm step <node>" DSL command - the "pg_autoctl manual fsm step [report|advance]" CLI split in docs/ref/pgaftest.rst (new "Step mode: no-autopilot nodes" section, node modifiers table, DSL command reference, test catalog entry) and docs/ref/pg_autoctl_manual.rst (fsm step synopsis).
1 parent 23a37d4 commit 6446d3c

5 files changed

Lines changed: 153 additions & 0 deletions

File tree

docs/ref/pg_autoctl_manual.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ stopped or stuck, and for low-level diagnostic work. Using them while
3434
step Make a state transition if instructed by the monitor
3535
+ nodes Manually manage the keeper's nodes list
3636

37+
``pg_autoctl manual fsm step [report|advance]`` normally does both halves of
38+
a step in one call: report the node's current state to the monitor, then
39+
immediately attempt whatever transition the monitor assigns back. Passing
40+
``report`` or ``advance`` as an argument splits that into its two
41+
independently-issuable halves — ``report`` reports the current state and
42+
returns without transitioning; ``advance`` attempts the transition the
43+
monitor already assigned, without re-reporting first. Neither half re-runs
44+
the other, so observing the effect of ``advance`` on the monitor's own view
45+
still needs a following ``report`` (or plain ``step``) call. This is mainly
46+
useful against a node started with ``pgaftest``'s ``no-autopilot`` cluster
47+
modifier (see :ref:`pgaftest <pgaftest>`), where the node-active service
48+
never ticks the FSM on its own — ``step``/``report``/``advance`` become the
49+
only way to move it forward, one call at a time.
50+
3751
pg_autoctl manual fsm nodes
3852
get Get the list of nodes from file (see --disable-monitor)
3953
set Set the list of nodes to file (see --disable-monitor)

docs/ref/pgaftest.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,10 @@ Node modifiers:
440440
(``--region``; default: ``default``)
441441
``launch deferred`` Container starts with ``sleep infinity``;
442442
use ``exec node pg_autoctl node start``
443+
``no-autopilot`` Step mode: the node-active service never
444+
transitions on its own; drive it explicitly
445+
with the ``fsm step <node>`` DSL command
446+
(see `Step mode: no-autopilot nodes`_ below)
443447
``coordinator`` / ``worker group <N>`` Citus role
444448
``no-monitor`` Standalone node (no monitor)
445449
``listen`` Bind all interfaces (``--listen 0.0.0.0``)
@@ -478,6 +482,39 @@ See "Deterministic node registration order" in
478482
and ``cli_node.c``).
479483

480484

485+
Step mode: ``no-autopilot`` nodes
486+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
487+
488+
A node declared with the ``no-autopilot`` modifier starts with
489+
``PG_AUTOCTL_STEP_MODE`` set, which changes what its node-active service does
490+
on each FSM tick: instead of reporting its current state to the monitor and
491+
immediately attempting whatever transition the monitor assigns back —
492+
atomically, on every tick, with no way to observe or freeze the moment in
493+
between — it opens a small Unix-domain-socket server and waits. Nothing
494+
happens to that node's FSM until the spec explicitly drives it with the
495+
``fsm step <node>`` command, documented under "Commands inside ``setup``,
496+
``teardown``, and ``step`` blocks" below.
497+
498+
This exists so a test can hold a node frozen at a specific reported state on
499+
purpose — e.g. to prove the monitor assigns the right next state before the
500+
node itself races off to reach it, or to reproduce a specific ordering
501+
between two nodes that would otherwise be a race under the normal, freely
502+
ticking FSM. Every other node in the same spec (without the modifier) keeps
503+
autopiloting normally; ``no-autopilot`` only affects the node(s) it's
504+
declared on.
505+
506+
``fsm step <node>`` is sugar for the combined
507+
``pg_autoctl manual fsm step`` command (report the current state, then
508+
immediately attempt whatever transition the monitor assigns). The underlying
509+
CLI also exposes the two halves separately as ``manual fsm step report`` and
510+
``manual fsm step advance`` — see :ref:`pg_autoctl_manual` — for scenarios
511+
that need to observe the monitor's assigned goal state before deciding
512+
whether, or when, to actually attempt the transition; the DSL does not yet
513+
have separate sugar for the split, so use ``exec <node> pg_autoctl manual
514+
fsm step report --pgdata /var/lib/postgres/pgaf`` / ``... advance ...``
515+
directly for that.
516+
517+
481518
Commands inside ``setup``, ``teardown``, and ``step`` blocks
482519
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
483520

@@ -575,6 +612,12 @@ node ...`` which queries the running node/monitor instead of the file.
575612
stop postgres <node>
576613
start postgres <node>
577614
615+
**FSM step** (``no-autopilot`` nodes only — see `Step mode: no-autopilot nodes`_ above)
616+
617+
.. code-block:: text
618+
619+
fsm step <node>
620+
578621
**Failover**
579622

580623
.. code-block:: text
@@ -762,6 +805,12 @@ Schedules under ``tests/tap/schedules/*.sch`` group these into CI jobs.
762805
``fast_forward``
763806
Test fast-forward stuck detection and recovery.
764807

808+
``fsm_step_report_advance``
809+
Test the ``pg_autoctl manual fsm step report``/``... advance`` split
810+
using a ``no-autopilot`` node: report a stale state to the monitor
811+
without transitioning, then advance to the transition the monitor
812+
already assigned, proving the two halves work independently.
813+
765814
``guard_data_loss``
766815
Test ``pgautofailover.guard_data_loss`` /
767816
``pg_autoctl perform failover --allow-data-loss``.

tests/tap/schedule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ multi_ifdown
2525
multi_maintenance
2626
multi_alternate
2727
guard_data_loss
28+
fsm_step_report_advance
2829
replication_stall_3dc
2930
fast_forward
3031
demote_timeout_wait_primary_deadlock

tests/tap/schedules/node.sch

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# count and GitHub Actions runner queue pressure.
44
create_standby_with_pgdata
55
launch_deferred_set_metadata
6+
fsm_step_report_advance
67
maintenance_and_drop
78
auth
89
monitor_disabled
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Regression spec for the new "pg_autoctl manual fsm step report"/"...
2+
# advance" split (src/bin/pg_autoctl/fsm.c's keeper_fsm_step_report/
3+
# _advance, service_keeper.c's step-mode socket dispatch, cli_do_fsm.c's
4+
# cli_do_fsm_step) -- see docs/ref/pgaftest.rst's own "Step mode" section
5+
# for the full protocol description.
6+
#
7+
# The combined "pg_autoctl manual fsm step" (and its pgaftest
8+
# "fsm step <node>" sugar) reports the current state to the monitor and,
9+
# in the very same call, immediately attempts whatever transition the
10+
# monitor just assigned -- atomically, with no way to observe (or hold a
11+
# node frozen at) the moment in between. "report" and "advance" split
12+
# that into two independently-issuable halves, so a test (or an operator
13+
# reproducing a race condition by hand) can freeze a node's own
14+
# reportedState at will and only decide later, explicitly, whether and
15+
# when it should attempt the transition the monitor already assigned.
16+
#
17+
# This spec proves the split mechanism itself, end to end, on the
18+
# simplest case that exercises it: node2 registers as node1's standby
19+
# (reaching reportedState catchingup), node1 is then forcibly removed,
20+
# leaving node2 alone in the group -- the monitor assigns node2's
21+
# goalState to single (an existing, pre-existing "alone in group ->
22+
# single" rule, unrelated to this spec's own point). node2 is running
23+
# no-autopilot (step mode), so:
24+
#
25+
# - "manual fsm step report" reports node2's unchanged current state
26+
# (catchingup) to the monitor and returns -- proven by the monitor
27+
# bumping goalState to single while reportedState stays catchingup.
28+
# - "manual fsm step advance" then performs the transition the
29+
# monitor already assigned (catchingup -> single), without
30+
# re-reporting first -- proven by reportedState becoming single.
31+
cluster {
32+
monitor
33+
formation {
34+
node1
35+
node2 no-autopilot
36+
}
37+
}
38+
39+
setup {
40+
wait until node2 state = catchingup timeout 60s
41+
}
42+
43+
teardown {
44+
compose down
45+
}
46+
47+
step test_001_remove_primary_leaving_node2_alone {
48+
sql monitor {
49+
SELECT pgautofailover.remove_node(nodehost, nodeport, true)
50+
FROM pgautofailover.node WHERE nodename = 'node1';
51+
}
52+
}
53+
54+
step test_002_node2_reports_and_learns_single {
55+
exec node2 pg_autoctl manual fsm step report --pgdata /var/lib/postgres/pgaf
56+
sql monitor {
57+
SELECT reportedstate FROM pgautofailover.node WHERE nodename = 'node2';
58+
}
59+
expect { catchingup }
60+
sql monitor {
61+
SELECT goalstate FROM pgautofailover.node WHERE nodename = 'node2';
62+
}
63+
expect { single }
64+
}
65+
66+
step test_003_node2_advances_to_single {
67+
exec node2 pg_autoctl manual fsm step advance --pgdata /var/lib/postgres/pgaf
68+
}
69+
70+
step test_004_node2_reports_the_new_single_state {
71+
# "advance" (like "report") only performs its own half of the split;
72+
# neither one re-reports afterward, so the monitor's own view of
73+
# node2 still lags until the next explicit "report" (or combined
74+
# "step") call pushes the now-current single state -- exactly the
75+
# same "one more call needed" shape the existing gap specs rely on
76+
# when chaining repeated combined "fsm step" calls.
77+
exec node2 pg_autoctl manual fsm step report --pgdata /var/lib/postgres/pgaf
78+
sql monitor {
79+
SELECT reportedstate FROM pgautofailover.node WHERE nodename = 'node2';
80+
}
81+
expect { single }
82+
}
83+
84+
sequence
85+
test_001_remove_primary_leaving_node2_alone
86+
test_002_node2_reports_and_learns_single
87+
test_003_node2_advances_to_single
88+
test_004_node2_reports_the_new_single_state

0 commit comments

Comments
 (0)