Skip to content

Commit a012bc1

Browse files
authored
Merge pull request #22 from cybertec-postgresql/multisite-v4.1.2
Merge in v4.1.2
2 parents a2a4995 + 70f3732 commit a012bc1

66 files changed

Lines changed: 927 additions & 288 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/mapping.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
versions = {'etcd': '9.6', 'etcd3': '16', 'consul': '17', 'exhibitor': '12', 'raft': '14', 'kubernetes': '15'}
1+
versions = {'etcd': '9.6', 'etcd3': '17', 'consul': '18', 'exhibitor': '12', 'raft': '14', 'kubernetes': '16'}

.github/workflows/tests.yaml

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
os: [ubuntu, windows, macos]
2121

2222
steps:
23-
- uses: actions/checkout@v4
23+
- uses: actions/checkout@v5
2424

2525
- name: Set up Python 3.7
2626
uses: actions/setup-python@v5
@@ -91,18 +91,25 @@ jobs:
9191
run: python .github/workflows/run_tests.py
9292
if: matrix.os != 'macos'
9393

94+
- name: Set up Python 3.14
95+
uses: actions/setup-python@v5
96+
with:
97+
python-version: 3.14
98+
if: matrix.os != 'macos'
99+
- name: Install dependencies
100+
run: python .github/workflows/install_deps.py
101+
if: matrix.os != 'macos'
102+
- name: Run tests and flake8
103+
run: python .github/workflows/run_tests.py
104+
if: matrix.os != 'macos'
105+
94106
- name: Combine coverage
95107
run: python .github/workflows/run_tests.py combine
96108

97-
- name: Install coveralls
98-
run: python -m pip install coveralls
99-
100-
- name: Upload Coverage
101-
env:
102-
COVERALLS_FLAG_NAME: unit-${{ matrix.os }}
103-
COVERALLS_PARALLEL: 'true'
104-
GITHUB_TOKEN: ${{ secrets.github_token }}
105-
run: python -m coveralls --service=github
109+
- name: Upload coverage reports to Codecov
110+
uses: codecov/codecov-action@v5
111+
with:
112+
flags: unit-${{ matrix.os }}
106113

107114
behave:
108115
runs-on: ${{ fromJson('{"ubuntu":"ubuntu-22.04","windows":"windows-latest","macos":"macos-14"}')[matrix.os] }}
@@ -114,7 +121,7 @@ jobs:
114121
fail-fast: false
115122
matrix:
116123
os: [ubuntu]
117-
python-version: [3.7, 3.13]
124+
python-version: [3.7, 3.14]
118125
dcs: [etcd, etcd3, consul, exhibitor, kubernetes, raft]
119126
include:
120127
- os: macos
@@ -128,12 +135,14 @@ jobs:
128135
dcs: etcd3
129136

130137
steps:
131-
- uses: actions/checkout@v4
138+
- uses: actions/checkout@v5
132139
- name: Set up Python
133140
uses: actions/setup-python@v5
134141
with:
135142
python-version: ${{ matrix.python-version }}
136143
- uses: nolar/setup-k3d-k3s@v1
144+
with:
145+
github-token: ${{ secrets.GITHUB_TOKEN }}
137146
if: matrix.dcs == 'kubernetes'
138147
- name: Add postgresql and citus apt repo
139148
run: |
@@ -164,17 +173,6 @@ jobs:
164173
run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r cobertura.xml -l Python --partial
165174
if: ${{ env.SECRETS_AVAILABLE == 'true' }}
166175

167-
coveralls-finish:
168-
name: Finalize coveralls.io
169-
needs: unit
170-
runs-on: ubuntu-latest
171-
steps:
172-
- uses: actions/setup-python@v5
173-
- run: python -m pip install coveralls
174-
- run: python -m coveralls --service=github --finish
175-
env:
176-
GITHUB_TOKEN: ${{ secrets.github_token }}
177-
178176
codacy-final:
179177
name: Finalize Codacy
180178
needs: behave
@@ -186,25 +184,25 @@ jobs:
186184
pyright:
187185
runs-on: ubuntu-latest
188186
steps:
189-
- uses: actions/checkout@v4
187+
- uses: actions/checkout@v5
190188

191-
- name: Set up Python 3.13
189+
- name: Set up Python 3.14
192190
uses: actions/setup-python@v5
193191
with:
194-
python-version: 3.13
192+
python-version: 3.14
195193

196194
- name: Install dependencies
197195
run: python -m pip install -r requirements.txt psycopg2-binary psycopg
198196

199197
- uses: jakebailey/pyright-action@v2
200198
with:
201-
version: 1.1.405
199+
version: 1.1.408
202200

203201
ydiff:
204202
name: Test compatibility with the latest version of ydiff
205203
runs-on: ubuntu-latest
206204
steps:
207-
- uses: actions/checkout@v4
205+
- uses: actions/checkout@v5
208206

209207
- name: Set up Python 3.13
210208
uses: actions/setup-python@v5
@@ -220,7 +218,7 @@ jobs:
220218
docs:
221219
runs-on: ubuntu-latest
222220
steps:
223-
- uses: actions/checkout@v4
221+
- uses: actions/checkout@v5
224222

225223
- name: Set up Python 3.11
226224
uses: actions/setup-python@v5
@@ -244,7 +242,7 @@ jobs:
244242
isort:
245243
runs-on: ubuntu-latest
246244
steps:
247-
- uses: actions/checkout@v4
245+
- uses: actions/checkout@v5
248246

249247
- name: Set up Python 3.12
250248
uses: actions/setup-python@v5

README.rst

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,55 @@
11
|Tests Status| |Coverage Status|
22

3+
.. image:: docs/_static/patroni-logo.svg
4+
:height: 128px
5+
:width: 128px
6+
37
Patroni: A Template for PostgreSQL HA with ZooKeeper, etcd or Consul
48
--------------------------------------------------------------------
59

610
You can find a version of this documentation that is searchable and also easier to navigate at `patroni.readthedocs.io <https://patroni.readthedocs.io>`__.
711

12+
**Important!**
13+
Running Patroni on **memory-restricted systems with Python 3.11+**
14+
15+
----
16+
17+
If you run Patroni on a system with strict memory limits, for example with ``vm.overcommit_memory=2`` (recommended for PostgreSQL), and use Python 3.11 or newer, you may observe unexpected behavior:
18+
19+
- Patroni appears healthy
20+
- PostgreSQL continues to run
21+
- Patroni **REST API becomes unresponsive**
22+
- The operating system reports that Patroni is listening on the REST API port
23+
- Patroni logs look normal; however, following messages may appear once: ``Exception ignored in thread started by: <object repr() failed>``, ``MemoryError``
24+
- Kernel logs may contain messages such as ``not enough memory for the allocation``
25+
26+
This behavior is caused by a `bug in Python 3.11+ <https://github.com/python/cpython/issues/140746>`__.
27+
Under strict memory conditions, starting a new thread may hang indefinitely when there is not enough free memory.
28+
29+
Recommended solution
30+
--------------------
31+
32+
Recent Patroni releases (4.1.1+, 4.0.8+) reduce the impact of this issue by starting all required threads early during startup, before the system is under memory pressure.
33+
34+
Additional recommendations (Linux, glibc)
35+
-----------------------------------------
36+
37+
When running with ``vm.overcommit_memory=2`` (recommended for PostgreSQL), we also recommend starting Patroni with the following environment variables configured:
38+
39+
- ``MALLOC_ARENA_MAX=1`` - reduces the amount of virtual memory allocated by glibc for multi-threaded
40+
applications
41+
- ``PG_MALLOC_ARENA_MAX=`` - resets the value of ``MALLOC_ARENA_MAX`` for PostgreSQL processes started by Patroni.
42+
43+
In addition, you may tune the following Patroni configuration parameters:
44+
45+
- ``thread_stack_size`` - stack size used for threads started by Patroni. Lowering this value reduces memory usage of the Patroni process. The default value set by Patroni is ``512kB``. Increase ``thread_stack_size`` if Patroni experience stack-related crashes; otherwise the default value is sufficient.
46+
- ``thread_pool_size`` - size of the thread pool used by Patroni for asynchronous tasks and REST API communication with other members during leader race or failsafe checks. The default value is ``5``, which is sufficient for three-node clusters.
47+
- ``restapi.thread_pool_size`` - size of the thread pool used to process REST API requests. The default value is ``5``, allowing up to five parallel REST API requests. Note that requests involving SQL queries are effectively serialized because a single database connection is used, so increasing this value typically provides no benefit.
48+
49+
----
50+
51+
PostgreSQL High Availability and Patroni
52+
----------------------------------------
853

954
There are many ways to run high availability with PostgreSQL; for a list, see the `PostgreSQL Documentation <https://wiki.postgresql.org/wiki/Replication,_Clustering,_and_Connection_Pooling>`__.
1055

@@ -173,5 +218,5 @@ When connecting from an application, always use a non-superuser. Patroni require
173218

174219
.. |Tests Status| image:: https://github.com/patroni/patroni/actions/workflows/tests.yaml/badge.svg
175220
:target: https://github.com/patroni/patroni/actions/workflows/tests.yaml?query=branch%3Amaster
176-
.. |Coverage Status| image:: https://coveralls.io/repos/patroni/patroni/badge.svg?branch=master
177-
:target: https://coveralls.io/github/patroni/patroni?branch=master
221+
.. |Coverage Status| image:: https://codecov.io/gh/patroni/patroni/graph/badge.svg?token=qWNJyFTeul
222+
:target: https://codecov.io/gh/patroni/patroni

docs/ENVIRONMENT.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ It is possible to override some of the configuration parameters defined in the P
88
Global/Universal
99
----------------
1010
- **PATRONI\_CONFIGURATION**: it is possible to set the entire configuration for the Patroni via ``PATRONI_CONFIGURATION`` environment variable. In this case any other environment variables will not be considered!
11+
- **PATRONI\_THREAD\_POOL\_SIZE**: size of thread pool used by Patroni to execute asynchronous tasks and communicate via REST API with other members during leader race or failsafe checks. Minimal value is ``5``, default value is ``5``.
12+
- **PATRONI\_THREAD\_STACK\_SIZE**: specifies the stack size to be used for threads started by Patroni. Value must be aligned by ``64kB``. Minimal value is ``64kB``, default value (set by Patroni) is ``512kB``.
1113
- **PATRONI\_NAME**: name of the node where the current instance of Patroni is running. Must be unique for the cluster.
1214
- **PATRONI\_NAMESPACE**: path within the configuration store where Patroni will keep information about the cluster. Default value: "/service"
1315
- **PATRONI\_SCOPE**: cluster name
16+
- **PG\_MALLOC\_ARENA\_MAX**: custom value for ``MALLOC_ARENA_MAX`` environment variable for ``postmaster`` process. If not set, ``postmaster`` will inherit ``MALLOC_ARENA_MAX`` value.
1417

1518
Log
1619
---
@@ -193,6 +196,7 @@ PostgreSQL
193196

194197
REST API
195198
--------
199+
- **PATRONI\_RESTAPI\_THREAD\_POOL\_SIZE**: size of thread pool used by Patroni to process REST API requests. Minimal value is ``5``, default value is ``5``.
196200
- **PATRONI\_RESTAPI\_CONNECT\_ADDRESS**: IP address and port to access the REST API.
197201
- **PATRONI\_RESTAPI\_LISTEN**: IP address and port that Patroni will listen to, to provide health-check information for HAProxy.
198202
- **PATRONI\_RESTAPI\_USERNAME**: Basic-auth username to protect unsafe REST API endpoints.

docs/_static/patroni-logo.png

16.7 KB
Loading

docs/_static/patroni-logo.svg

Lines changed: 9 additions & 0 deletions
Loading

docs/existing_data.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ You can find below an overview of steps for converting an existing Postgres clus
3838

3939
#. Create a YAML configuration file for Patroni. You can use :ref:`Patroni configuration generation and validation tooling <validate_generate_config>` for that.
4040

41-
* **Note (specific for the primary node):** If you have replication slots being used for replication between cluster members, then it is recommended that you enable ``use_slots`` and configure the existing replication slots as permanent via the ``slots`` configuration item. Be aware that Patroni automatically creates replication slots for replication between members, and drops replication slots that it does not recognize, when ``use_slots`` is enabled. The idea of using permanent slots here is to allow your existing slots to persist while the migration to Patroni is in progress. See :ref:`YAML Configuration Settings <yaml_configuration>` for details.
41+
* **Note (specific for the primary node):** If you have replication slots being used for replication between cluster members, then it is recommended that you enable ``use_slots`` and configure the existing replication slots as permanent via the ``slots`` configuration item. Be aware that Patroni automatically creates replication slots for replication between members, and drops replication slots that it does not recognize, when ``use_slots`` is enabled. The idea of using permanent slots here is to allow your existing slots to persist while the migration to Patroni is in progress. See :ref:`Dynamic Configuration Settings <dynamic_configuration>` for details.
4242

4343
#. Start Patroni using the ``patroni`` systemd service unit. It automatically detects that Postgres is already running and starts monitoring the instance.
4444

@@ -47,7 +47,7 @@ You can find below an overview of steps for converting an existing Postgres clus
4747
#. Immediate restart of the standby nodes.
4848
#. Scheduled restart of the primary node within a maintenance window.
4949

50-
#. If you configured permanent slots in step ``1.2.``, then you should remove them from ``slots`` configuration through :ref:`patronictl edit-config cluster-name member-name <patronictl_edit_config_parameters>` command once the ``restart_lsn`` of the slots created by Patroni is able to catch up with the ``restart_lsn`` of the original slots for the corresponding members. By removing the slots from ``slots`` configuration you will allow Patroni to drop the original slots from your cluster once they are not needed anymore. You can find below an example query to check the ``restart_lsn`` of a couple slots, so you can compare them:
50+
#. If you configured permanent slots in step ``1.2.``, then you should remove them from ``slots`` configuration through :ref:`patronictl edit-config cluster-name <patronictl_edit_config_parameters>` command once the ``restart_lsn`` of the slots created by Patroni is able to catch up with the ``restart_lsn`` of the original slots for the corresponding members. By removing the slots from ``slots`` configuration you will allow Patroni to drop the original slots from your cluster once they are not needed anymore. You can find below an example query to check the ``restart_lsn`` of a couple slots, so you can compare them:
5151

5252
.. code-block:: sql
5353

docs/faq.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ How can I change my environment configuration?
157157

158158
Take care to not cause a failover in the cluster! You might be interested in checking :ref:`patronictl_pause`.
159159

160+
How can I reduce repetitive heartbeat log lines during normal operation?
161+
If your logs are too noisy because of repeated lines like ``Lock owner: ...`` and ``no action. I am ...``,
162+
configure ``log.deduplicate_heartbeat_logs: true``.
163+
164+
You can set it either in the Patroni YAML file (:ref:`log_settings`) or with
165+
``PATRONI_LOG_DEDUPLICATE_HEARTBEAT_LOGS=true``.
166+
167+
Keep in mind this reduces log volume by suppressing repeated heartbeat messages, but you also lose per-loop
168+
heartbeat visibility that can help during failover diagnostics.
169+
160170
What occurs if I change a Postgres GUC that requires a reload?
161171
When you change the dynamic or the local configuration as explained in the previous questions, Patroni will take care of reloading the Postgres configuration for you.
162172

docs/ha_multi_dc.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
HA multi datacenter
55
===================
66

7-
The high availability of a PostgreSQL cluster deployed in multiple data centers is based on replication, which can be synchronous or asynchronous (`replication_modes <replication_modes.rst>`_).
7+
The high availability of a PostgreSQL cluster deployed in multiple data centers is based on replication, which can be synchronous or asynchronous (see :ref:`replication modes <replication_modes>`).
88

99
In both cases, it is important to be clear about the following concepts:
1010

0 commit comments

Comments
 (0)