patroni.postgresql.sync module

class patroni.postgresql.sync.SyncHandler(postgresql: Postgresql)

Bases: object

Class responsible for working with the synchronous_standby_names.

Sync standbys are chosen based on their state in pg_stat_replication. When synchronous_standby_names is changed we memorize the _primary_flush_lsn and the current_state() method will count newly added names as “sync” only when they reached memorized LSN and also reported as “sync” by pg_stat_replication

current_state(cluster: Cluster) Tuple[CaseInsensitiveSet, CaseInsensitiveSet]

Find the best candidates to be the synchronous standbys.

Current synchronous standby is always preferred, unless it has disconnected or does not want to be a synchronous standby any longer.

Standbys are selected based on values from the global configuration:

  • maximum_lag_on_syncnode: would help swapping unhealthy sync replica in case if it stops responding (or hung). Please set the value high enough so it won’t unncessarily swap sync standbys during high loads. Any value less or equal of 0 keeps the behavior backward compatible. Please note that it will not also swap sync standbys in case where all replicas are hung.

  • synchronous_node_count: controlls how many nodes should be set as synchronous.

Returns:

tuple of candidates CaseInsensitiveSet and synchronous standbys CaseInsensitiveSet.

set_synchronous_standby_names(sync: Collection[str]) None

Constructs and sets “synchronous_standby_names” GUC value.

Parameters:

sync – set of nodes to sync to

patroni.postgresql.sync.parse_sync_standby_names(value: str) _SSN

Parse postgresql synchronous_standby_names to constituent parts.

Parameters:

value – the value of synchronous_standby_names

Returns:

_SSN object

Raises:

ValueError – if the configuration value can not be parsed

>>> parse_sync_standby_names('').sync_type
'off'
>>> parse_sync_standby_names('FiRsT').sync_type
'priority'
>>> 'first' in parse_sync_standby_names('FiRsT').members
True
>>> set(parse_sync_standby_names('"1"').members)
{'1'}
>>> parse_sync_standby_names(' a , b ').members == {'a', 'b'}
True
>>> parse_sync_standby_names(' a , b ').num
1
>>> parse_sync_standby_names('ANY 4("a",*,b)').has_star
True
>>> parse_sync_standby_names('ANY 4("a",*,b)').num
4
>>> parse_sync_standby_names('1')  
Traceback (most recent call last):
    ...
ValueError: Unparseable synchronous_standby_names value
>>> parse_sync_standby_names('a,')  
Traceback (most recent call last):
    ...
ValueError: Unparseable synchronous_standby_names value
>>> parse_sync_standby_names('ANY 4("a" b,"c c")')  
Traceback (most recent call last):
    ...
ValueError: Unparseable synchronous_standby_names value
>>> parse_sync_standby_names('FIRST 4("a",)')  
Traceback (most recent call last):
    ...
ValueError: Unparseable synchronous_standby_names value
>>> parse_sync_standby_names('2 (,)')  
Traceback (most recent call last):
    ...
ValueError: Unparseable synchronous_standby_names value
patroni.postgresql.sync.quote_ident(value: str) str

Very simplified version of psycopg quote_ident() function.