Commit Graph
2429 Commits
Author SHA1 Message Date
Alexander KukushkinandGitHub 6d65aa311a Configurable retention of members replication slots (#3108)
Current problem of Patroni that strikes many people is that it removes replication slot for member which key is expired from DCS. As a result, when the replica comes back from a scheduled maintenance WAL segments could be already absent, and it can't continue streaming without pulling files from archive.
With PostgreSQL 16 and newer we get another problem: logical slot on a standby node could be invalidated if physical replication slot on the primary was removed (and `pg_catalog` vacuumed).
The most problematic environment is Kubernetes, where slot is removed nearly instantly when member Pod is deleted.

So far, one of the recommended solutions was to configure permanent physical slots with names that match member names to avoid removal of replication slots. It works, but depending on environment might be non-trivial to implement (when for example members may change their names).

This PR implements support of `member_slots_ttl` global configuration parameter, that controls for how long member replication slots should be kept when the member key is absent. Default value is set to `30min`.
The feature is supported only starting from PostgreSQL 11 and newer, because we want to retain slots not only on the leader node, but on all nodes that could potentially become the new leader, and they should be moved forward using `pg_replication_slot_advance()` function.

One could disable feature and get back to the old behavior by setting `member_slots_ttl` to `0`.
2024-08-23 14:50:36 +02:00
Polina BunginaandGitHub 8c5ab4c07d Improve GUCs validation (#3130)
Due to postgres --describe-config not showing GUCs defined as GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE, Patroni was always ignoring some GUCs that a user might want to have configured with non-default values.

- remove postgres --describe-config validation.
- define minor versions for availability bounds of some back-patched GUCs
2024-08-23 14:20:16 +02:00
Polina BunginaandGitHub 31cf951b69 Remove patronictl failover --leader option (#3129)
Option has been deprecated and should be removed in the new major release
2024-08-16 10:18:18 +02:00
WaynervandGitHub 7659ccd50b Fix request URL in failsafe handling logs (#3126) 2024-08-15 16:39:56 +02:00
WaynervandGitHub a03dba04e3 Fix timestamp order in postmaster check log (#3128) 2024-08-15 15:39:24 +02:00
Alexander KukushkinandGitHub 93eb4edbe6 Reformat imports with isort (#3123)
Besides that:
1. Introduce `setup.py isort` for quick check
2. Introduce GH actions to check imports
2024-08-13 17:53:59 +02:00
GuanqunYang193andGitHub c931da1eb3 Remove user creation (#2894)
It was announced as deprecated in v3.2.0
2024-08-13 15:55:58 +02:00
Polina BunginaandGitHub fc5a8ed01c Add synchronous_node_count to dynamic conf doc (#3124) 2024-08-13 15:28:37 +02:00
Alexander KukushkinandGitHub 0fa41502f1 Register Citus secondaries in pg_dist_node (#2755)
1. All nodes with role == 'replica' and state == 'running' are are registered. In case is state isn't running the node is removed.
2. In case of failover/switchover we always first update the primary
3. When switching to a registered secondary we call citus_update_node() three times: rename primary to primary-demoted, put the primary name to a promoted secondary row and put the promoted secondary name to the primary row

State transitions are produced by the transition() method. First of all the method makes sure that the actual primary is registered in the metadata. In case if for a given group the primary didn't change, the method registers new secondaries and removes secondaries that are gone. It prefers to use citus_update_node() UDF to replace gone secondaries with added.

Communication protocol between primary nodes remains the same and all old features work without any changes.
2024-08-13 09:12:03 +02:00
Alexander KukushkinandGitHub 384705ad97 Quorum based failover (#2668)
To enable quorum commit:
```diff
$ patronictl.py edit-config
--- 
+++ 
@@ -5,3 +5,4 @@
   use_pg_rewind: true
 retry_timeout: 10
 ttl: 30
+synchronous_mode: quorum

Apply these changes? [y/N]: y
Configuration changed
```

By default Patroni will use `ANY 1(list,of,stanbys)` in `synchronous_standby_names`. That is, only one node out of listed replicas will be used for quorum.
If you want to increase the number of quorum nodes it is possible to do it with:
```diff
$ patronictl edit-config
--- 
+++ 
@@ -6,3 +6,4 @@
 retry_timeout: 10
 synchronous_mode: quorum
 ttl: 30
+synchronous_node_count: 2

Apply these changes? [y/N]: y
Configuration changed
```

Good old `synchronous_mode: on` is still supported.

Close https://github.com/patroni/patroni/issues/664
Close https://github.com/zalando/patroni/pull/672
2024-08-13 08:51:01 +02:00
Alexander KukushkinandGitHub 56dba93c55 Implement support of log.mode. (#3122)
There was one oversight of #2781 - to influence external tools that Patroni could execute, we set global `umask` value based on permissions of the $PGDATA directory. As a result, it also influenced permissions of log files created by Patroni.

To address the problem we implement two measures:
1. Make `log.mode` configurable.
2. If the value is not set - calculate permissions from the original value of the umask setting.
2024-08-13 08:11:28 +02:00
Alexander KukushkinandGitHub b458bd992a Use get_parameter_status() method instead of Connection.info.parameter_status() (#3119)
The last one is only available since psycopg 2.8, while the first one since 2.0.8.
For backward compatibility monkeypatch connection object returned by psycopg3.

Close https://github.com/patroni/patroni/issues/3116
2024-08-12 15:17:36 +02:00
Alexander KukushkinandGitHub 5eb431b719 Compatibility with v17 beta3 (#3120)
`standby_slot_names` was renamed to `synchronized_standby_slots`
2024-08-12 10:53:50 +02:00
Alexander KukushkinandGitHub ab9faf9471 Ignore restapi.allowlist_include_members for POST /failsafe (#3113)
If only the leader can't access DCS its member key will expire and `POST /failsafe` requests might be rejected because of that.

Close #3096
2024-07-30 13:22:37 +02:00
Alexander KukushkinandGitHub cd3f52b029 Don't let the current node be chosen as synchronous (#3112)
It could happen that there is "something" streaming from the current primary node with `application_name` that matches name of the current primary, for instance due to a faulty configuration. When processing `pg_stat_replication` we only checked that the `application_name` matches with the name one of the member nodes, but we forgot to exclude our own name.
As a result there were following side-effects:
1. The current primary could be declared as a synchronous node.
2. As a result of [1] it wasn't possible to do a switchover.
3. During shutdown the current primary was waiting for itself to release it from synchronous nodes.

Close #3111
2024-07-29 15:43:16 +02:00
Alexander KukushkinandGitHub 4456e267eb Patroni doesn't forece wal_log_hints anymore (#3109)
We forgot to update it in https://github.com/patroni/patroni/pull/3063
2024-07-22 09:42:37 +02:00
Alexander KukushkinandGitHub c6339234c6 Refactor update_leader() method (#3107)
Pass the `Cluster` object instead of `Leader`.
It will help to implement a new feature, "Configurable retention of replication slots for cluster members".

Besides that fix a couple of issues with docstrings.
2024-07-18 08:28:54 +02:00
Alexander KukushkinandGitHub b1d442e7a4 Advance permanent slots for cascading nodes while in failsafe (#3100)
Lets consider a following replication setup:
```
primary->standby1->standby2(replicatefrom: standby1)
```

In this case the `primary` will not create a physical replication slot for standby2, because it is streaming from the `standby1`.

Things will look differently if we have the following dynamic configuration:
```yaml
slots:
    primary:
        type: physical
    standby1:
        type: physical
    standby2:
        type: physical
```

In this case `primary` will also have `standby2` physical replication slot, which periodically must be advanced. So far it was working by taking value of `xlog_location` from the `/members/standby2` key in DCS.

But, when DCS is down and failsafe mode is activate, the `standby2` physical slot on the `primary` will not not be moved, because there was not way to get the latest value of `xlog_location`.

This PR is addressing the problem by making replica nodes to return their `xlog_location` as `lsn` header in the response on `POST /failsafe` REST API request. The current primary will use these values to advance replication slots for nodes with `replicatefrom` tag.
2024-07-17 16:28:30 +02:00
Alexander KukushkinandGitHub b8b5518e8c Get rid of SLOT_ADVANCE_AVAILABLE_VERSION in dcs/__init__.py (#3105)
This constant was imported in `postgresql/__init__.py` and used in the `can_advance_slots` property.
But, after refactoring in #2958 we pass around a reference to `Postgresql` instead of `major_version` and therefore we can just rely on `can_advance_slots` property and don't reimplement its logic in other places.
2024-07-17 09:41:58 +02:00
Alexander KukushkinandGitHub a5796a03f1 Finish refactoring of the Status class (#3103)
The `Status` class was introduced in #2853, but we kept old properties in the `Cluster` object in order to have fewer changes in the rest of the code.

This PR is finishing the refactoring.
The following adjustments were made:
- Introduced `Status.is_empty()` method, which is used in the `Cluster.is_empty()` instead of checking actual values to simplify introduction of further fields to the Status object.
- Removed `Cluster.last_lsn` property
- Changed `Cluster.slots` property to always return dict and perform sanity checks on values.

Besides that, this PR addressing a couple of problems:
- the `AbstractDCS.get_cluster()` method some properties without holding a lock on `_cluster_thread_lock`.
- `Cluster.__permanent_slots` property was setting 'lsn' from all cluster members, while it should be doing that only for members with `replicatefrom` tag.
2024-07-16 09:47:20 +02:00
Polina BunginaandGitHub fbbd32a537 Release v3.3.2 (#3099)
* Update release notes, bump version
* Fix rn
* Bump pyright
2024-07-11 13:01:57 +02:00
Alexander KukushkinandGitHub c687838074 Fix race condition with logical slot advance and copy (#3098)
The `SlotsAdvanceThread` is asynchronously calling
pg_replication_slot_advance() and providing feedback about logical
replication slots that must be reinitialized by copying from the
primary. That is, the parent thread will learn about slots to be copied
only when scheduling the next pg_replication_slot_advance() call.
As a result it was possible situation when logical slot was copied with
PostgreSQL restart more than once.

To improve it we implement following measures:
1. do not schedule slot sync if it is in the list to be copied
2. remove to be copued slots from the `self._scheduled` structure
3. clean state of `SlotsAdvanceThread` when slot files are copied.
2024-07-10 17:40:17 +02:00
Polina BunginaandGitHub 622d41c83c Handle logical slots invalidation on a standby (#3097)
Since PG16 logical replication slots on a standby can be invalidated due
to horizon. In this case, pg_replication_slot_advance() will fail with
ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE. We should force slot copy
(i.e., recreation) of such slots.
2024-07-10 09:28:24 +02:00
RMTandGitHub f00826d6e6 Make `postgresql.parameter` documentation more clear (#3092) 2024-07-10 08:16:03 +02:00
IsraelandGitHub a4a6dc0299 Fix plain Postgres synchronous replication mode (#3094)
Since `synchronous_mode` was introduced to Patroni, the plain Postgres synchronous replication has been no longer working.

The issue occurs because `process_sync_replication` always resets the value of `synchronous_standby_names` in Postgres when `synchronous_mode` is disabled in Patroni.

This commit fixes that issue by setting the value of `synchronous_standby_names` as configured by the user, if that is the case, when `synchronous_mode` is disabled.

Closes #3093
References: PAT-254.
2024-07-02 16:06:42 +02:00
Polina BunginaandGitHub 3c07410695 Use trusted publishers for pypi (#3095) 2024-07-01 10:47:33 +02:00
Polina BunginaandGitHub 7067d744c6 Fix release notes indent (#3088) 2024-06-17 18:41:00 +02:00
6b7ec49282 Release v3.3.1 (#3087)
* Update release notes
* Bump version
* Bump pyright version and solve reported issues

---------

Co-authored-by: Alexander Kukushkin <[email protected]>
2024-06-17 17:45:10 +02:00
Polina BunginaandGitHub d4fd782038 Change all links and org references (#3086)
* Change all links and org references

* Update coverage status badge
2024-06-17 10:28:21 +02:00
Polina BunginaandGitHub 6e1f9f7a6e Prepare repo migration (#3085) 2024-06-17 09:04:43 +02:00
Alexander KukushkinandGitHub a5d095e316 Don't socket.getaddrinfo() from config_generator.py (#3082)
the get_address() function was called when config_generator.py is loaded because it was required to initialize `_HOSTNAME` and `_IP` properties of `AbstractConfigGenerator` and in some cases making unit tests very slow.
2024-06-17 08:05:09 +02:00
Polina BunginaandGitHub 2a003a36bb Adjust allow_in_place_tablespaces availability (#3081) 2024-06-14 09:47:57 +02:00
Alexander KukushkinandGitHub af03c619ec Standby cluster can't have synchronous nodes (#3079)
`synchronous_standby_names` and synchronous replication only work on a real primary node and in case of cascading replication simply ignored by Postgres.
This fact was already addressed by `global_config.is_synchronous_mode`, but in case if in a standby cluster the `/sync` key in DCS is not empty, `patronictl list` and `GET /cluster` were falsely reporting some nodes as synchronous because this check was missing.

Close https://github.com/zalando/patroni/issues/3078
2024-06-14 09:16:57 +02:00
Polina BunginaandGitHub 14a44e14ba Re-enable SSL for MacOS GH action runners (#3005) 2024-06-12 13:28:01 +02:00
Alexandre DetisteandGitHub dc7ba3fe15 drop dependency on ancient mock (#3074) 2024-06-12 10:47:18 +02:00
Alexander KukushkinandGitHub 1ed207cbf0 Compatibility with 17-beta1 (#3076)
- updated list of GUCs
- updated regex for filtering backend processes by name
- `primary_conninfo` will contain `dbname` parameter

The last one is required for synchronizing logical replication slots by slotsync worker and doesn't create problems on older versions.
2024-06-12 10:29:52 +02:00
Alexander KukushkinandGitHub b6c5a12017 Fix infinite recursion in in replicatefrom tags (#3072)
Besides that:
1. fix problem with is_physical_slot() methods, it was returning false positives for logical slots.
2. Fix a little issue with replicatefrom docs.

Close https://github.com/zalando/patroni/issues/3068
2024-06-12 10:26:18 +02:00
Alexander KukushkinandGitHub 1b7b8e60fb Refactor format_dsn() method (#3069)
so that it doesn't take any decisions about which keywords should appear in the connection string and just uses a provided dict.
2024-06-11 12:12:36 +02:00
jostaubandGitHub 0a91948a49 Doc improvement: mention requirement to use gRPC gateway with EtcdV3 (#3073) 2024-06-11 12:12:00 +02:00
Paul_KimandGitHub 0a6c09e252 Make wal_log_hints configurable (#3063)
Close #1942
2024-05-24 09:55:26 +02:00
Hedley RoosandGitHub ff31f45226 Instruct etcd to delete old revisions (#3024)
Etcd keeps old revisions unless instructed to delete them. If we don't delete old revisions then etcd memory usage will keep growing forever due to keepalive updates. Since Patroni does not really need to roll back to older revisions we can safely delete them.
2024-05-13 11:21:06 +02:00
Alexander KukushkinandGitHub ff99d29e6d Add date to every released version (#3057)
Going to GH releases and/or tags to get it is not very convinient.
2024-05-07 09:53:35 +02:00
Alexander KukushkinandGitHub 03bb9125cb Compatibility with python 3.12 (#3058)
- monkey patch `jsonlogger.RESERVED_ATTRS` to hide new attribute in `LogRecord`
- "silence" warning about `atetime.datetime.utcnow()`
- run some tests with python 3.12
- bump actions versions to silence complains about Node version
- fix PATH to Postgres binaries on MacOS
2024-05-07 09:29:28 +02:00
LUTIC NICOLASandGitHub 634b44ee05 Update contributing link (#3047) 2024-04-09 16:07:11 +02:00
WaynervandGitHub 290d05c642 Log pg_basebackup command in DEBUG level (#3045) 2024-04-09 15:19:00 +02:00
9d231aeecd Fix readthedocs builds (#3046)
- Mitigate removal of the -E build option (rtd now reuses build env)
- Fix psycopg module's docs
- Properly remove modules/* docs for epub and latex

---------

Co-authored-by: Alexander Kukushkin <[email protected]>
2024-04-08 08:28:20 +02:00
48fbf64ea9 Release v3.3.0 (#3043)
* Make sure tests are not making external calls
and pass url with scheme to urllib3 to avoid warnings

* Make sure unit tests not rely on filesystem state

* Bump pyright and "solve" reported "issues"

Most of them are related to partially unknown types of values from empty
dict or list. To solve it for the empty dict we use `EMPTY_DICT` object of
newly introduced `_FrozenDict` class.

* Improve unit-tests code coverage

* Add release notes for 3.3.0

* Bump version

* Fix pyinstaller spec file

* python 3.6 compatibility

---------

Co-authored-by: Polina Bungina <[email protected]>
v3.3.0
2024-04-04 17:51:26 +02:00
Alexander KukushkinandGitHub 3fd7c98d2b Compatibility with ydiff>=1.3 (#3042)
PatchStream class was removed as it was effectively doing nothing useful.
2024-04-02 14:48:58 +02:00
Alexander KukushkinandGitHub d7454f7bcd Use target_session_attrs only when multiple hosts in standby_cluster (#3040)
Actually comment in the code was already saying that, but on practice it didn't happen.

It should help #3039
2024-04-02 11:59:57 +02:00
WaynervandGitHub ceb2965ab8 Use importlib_resources to read validators file (#3018)
When packaged into pyz (zip file), resources are not directly available on filesystem and therefore we can't always rely on os.listdir() and open() to enumerate and read them.

We are going to use importlib.resources() to solve this problem, except python 3.8 and older, where there is no function (files()) available to enumerate resources. For legacy (3.8 actually becomes EOL in October 2024) python versions we are going to use os.listdir() as a fallback.

Close #3017
2024-04-02 09:00:37 +02:00