@startuml

title auto-HA node states
[*] --> single
single --> wait_primary : another node has joined
wait_primary --> primary : secondary is within\n1 WAL segment\nof the primary
primary -->draining : perform_failover() called\nor primary unhealthy
draining --> demote_timeout : secondary confirms\nit's receiving\nno more writes
demote_timeout --> demoted : demote timeout\nexpired
demoted --> catching_up : the old secondary\nis now wait_primary
[*] --> wait_standby
wait_standby --> catching_up : the primary has\nentered wait_primary
catching_up --> secondary : standby is within\n1 WAL segment\nof the primary
secondary --> catching_up : secondary is\nunhealthy
secondary --> prepare_promotion : primary failed or\nperform_failover() called
prepare_promotion --> stop_replication : caught up with primary\nor primary timed out
stop_replication --> wait_primary : demote timeout\nexpired
primary --> wait_primary : secondary is\nunhealthy

primary --> demote_timeout : † begin shutdown process\nif primary loses contact\nwith the other nodes\n(will transition back to\nprimary if it reestablishes\ncomms with monitor)

primary --> demoted : †
draining --> demoted : †

single : only node in the system, acting as primary
note right of single
  it would complicate the diagram
  to add all the transitions but
  this is always reachable
  (if the other node is removed)
end note
wait_primary : there is a secondary, but it's catching up
wait_standby : waiting for the primary to create a replication slot
primary : There is a secondary and it's caught up
draining : marked unhealthy, stop writes
demote_timeout : waiting for drain timeout to expire
demoted : drain timeout expired, node should be down
catching_up : following a primary but not caught up
secondary : following a primary, caught up
prepare_promotion : secondary doesn't converge to this
prepare_promotion : state until it has caught up with the
prepare_promotion : primary or timed-out trying
stop_replication : stop replication to cut off primary

note right of primary
  The transitions marked † are never
  taken by the monitor but might be
  experienced by the primary if it is down
  for a while and never checks in to notice
  that it's supposed to be in "draining", for
  example
end note

@enduml
