mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-26 23:50:23 +00:00
The /leader endpoint returns 200 if node holds the lock (#1917)
Promoting the standby cluster requires updating load-balancer health checks, which is not very convenient and easy to forget. In order to solve it, we change the behavior of the `/leader` health-check endpoint. It will return 200 without taking into account whether PostgreSQL is running as the primary or the standby_leader.
This commit is contained in:
+5
-4
@@ -9,14 +9,17 @@ Health check endpoints
|
||||
----------------------
|
||||
For all health check ``GET`` requests Patroni returns a JSON document with the status of the node, along with the HTTP status code. If you don't want or don't need the JSON document, you might consider using the ``OPTIONS`` method instead of ``GET``.
|
||||
|
||||
- The following requests to Patroni REST API will return HTTP status code **200** only when the Patroni node is running as the leader:
|
||||
- The following requests to Patroni REST API will return HTTP status code **200** only when the Patroni node is running as the primary with leader lock:
|
||||
|
||||
- ``GET /``
|
||||
- ``GET /master``
|
||||
- ``GET /leader``
|
||||
- ``GET /primary``
|
||||
- ``GET /read-write``
|
||||
|
||||
- ``GET /standby-leader``: returns HTTP status code **200** only when the Patroni node is running as the leader in a :ref:`standby cluster <standby_cluster>`.
|
||||
|
||||
- ``GET /leader``: returns HTTP status code **200** when the Patroni node has the leader lock. The major difference from the two previous endpoints is that it doesn't take into account whether PostgreSQL is running as the ``primary`` or the ``standby_leader``.
|
||||
|
||||
- ``GET /replica``: replica health check endpoint. It returns HTTP status code **200** only when the Patroni node is in the state ``running``, the role is ``replica`` and ``noloadbalance`` tag is not set.
|
||||
|
||||
- ``GET /replica?lag=<max-lag>``: replica check endpoint. In addition to checks from ``replica``, it also checks replication latency and returns status code **200** only when it is below specified value. The key cluster.last_leader_operation from DCS is used for Leader wal position and compute latency on replica for performance reasons. max-lag can be specified in bytes (integer) or in human readable values, for e.g. 16kB, 64MB, 1GB.
|
||||
@@ -28,8 +31,6 @@ For all health check ``GET`` requests Patroni returns a JSON document with the s
|
||||
|
||||
- ``GET /read-only``: like the above endpoint, but also includes the primary.
|
||||
|
||||
- ``GET /standby-leader``: returns HTTP status code **200** only when the Patroni node is running as the leader in a :ref:`standby cluster <standby_cluster>`.
|
||||
|
||||
- ``GET /synchronous`` or ``GET /sync``: returns HTTP status code **200** only when the Patroni node is running as a synchronous standby.
|
||||
|
||||
- ``GET /asynchronous`` or ``GET /async``: returns HTTP status code **200** only when the Patroni node is running as an asynchronous standby.
|
||||
|
||||
+6
-2
@@ -108,9 +108,11 @@ class RestApiHandler(BaseHTTPRequestHandler):
|
||||
response.get('role') == 'replica' and response.get('state') == 'running' else 503
|
||||
|
||||
if not cluster and patroni.ha.is_paused():
|
||||
leader_status_code = 200 if response.get('role') in ('master', 'standby_leader') else 503
|
||||
primary_status_code = 200 if response.get('role') == 'master' else 503
|
||||
standby_leader_status_code = 200 if response.get('role') == 'standby_leader' else 503
|
||||
elif patroni.ha.is_leader():
|
||||
leader_status_code = 200
|
||||
if patroni.ha.is_standby_cluster():
|
||||
primary_status_code = replica_status_code = 503
|
||||
standby_leader_status_code = 200 if response.get('role') in ('replica', 'standby_leader') else 503
|
||||
@@ -118,13 +120,15 @@ class RestApiHandler(BaseHTTPRequestHandler):
|
||||
primary_status_code = 200
|
||||
standby_leader_status_code = 503
|
||||
else:
|
||||
primary_status_code = standby_leader_status_code = 503
|
||||
leader_status_code = primary_status_code = standby_leader_status_code = 503
|
||||
|
||||
status_code = 503
|
||||
|
||||
if 'standby_leader' in path or 'standby-leader' in path:
|
||||
status_code = standby_leader_status_code
|
||||
elif 'master' in path or 'leader' in path or 'primary' in path or 'read-write' in path:
|
||||
elif 'leader' in path:
|
||||
status_code = leader_status_code
|
||||
elif 'master' in path or 'primary' in path or 'read-write' in path:
|
||||
status_code = primary_status_code
|
||||
elif 'replica' in path:
|
||||
status_code = replica_status_code
|
||||
|
||||
+5
-1
@@ -174,7 +174,7 @@ class TestRestApiHandler(unittest.TestCase):
|
||||
MockRestApiServer(RestApiHandler, 'GET /replica')
|
||||
with patch.object(RestApiHandler, 'get_postgresql_status', Mock(return_value={'state': 'running'})):
|
||||
MockRestApiServer(RestApiHandler, 'GET /health')
|
||||
MockRestApiServer(RestApiHandler, 'GET /master')
|
||||
MockRestApiServer(RestApiHandler, 'GET /leader')
|
||||
MockPatroni.dcs.cluster.sync.members = [MockPostgresql.name]
|
||||
MockPatroni.dcs.cluster.is_synchronous_mode = Mock(return_value=True)
|
||||
with patch.object(RestApiHandler, 'get_postgresql_status', Mock(return_value={'role': 'replica'})):
|
||||
@@ -507,3 +507,7 @@ class TestRestApiServer(unittest.TestCase):
|
||||
Mock(return_value=(mock_request, mock_address))
|
||||
):
|
||||
self.srv._handle_request_noblock()
|
||||
|
||||
@patch('ssl._ssl._test_decode_cert', Mock())
|
||||
def test_reload_local_certificate(self):
|
||||
self.assertTrue(self.srv.reload_local_certificate())
|
||||
|
||||
Reference in New Issue
Block a user