From 0e0b36430251cf8156fb0daef89b2e9d16df874f Mon Sep 17 00:00:00 2001 From: Julien Riou Date: Mon, 15 Apr 2019 14:49:54 +0200 Subject: [PATCH] Add read-only and read-write API routes (#1038) Patroni is great behind a load balancer like HAProxy. API routes are handy to direct the traffic to a valid node depending on its role. We could have one route for writes directed to the primary node and one route for reads directed to the replicas. In a two nodes setup, when we lose a node, there's one host left: the primary. Then, the read traffic will be dropped, even if the primary can handle it. This commit adds read-only and read-write routes. Read-only route enables reads on the primary. Read-write route is an alias for '/master', '/primary' or '/leader' route. --- patroni/api.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/patroni/api.py b/patroni/api.py index e89d00c6..e0754848 100644 --- a/patroni/api.py +++ b/patroni/api.py @@ -85,19 +85,22 @@ class RestApiHandler(BaseHTTPRequestHandler): patroni = self.server.patroni cluster = patroni.dcs.cluster + if not cluster and patroni.ha.is_paused(): + primary_status_code = 200 if response['role'] == 'master' else 503 + else: + primary_status_code = 200 if patroni.ha.is_leader() else 503 + replica_status_code = 200 if not patroni.noloadbalance and response.get('role') == 'replica' else 503 status_code = 503 if patroni.ha.is_standby_cluster() and ('standby_leader' in path or 'standby-leader' in path): status_code = 200 if patroni.ha.is_leader() else 503 - elif 'master' in path or 'leader' in path or 'primary' in path: - # Round-robing across all masters in pause mode if DCS is not accessible - if not cluster and patroni.ha.is_paused(): - status_code = 200 if response['role'] == 'master' else 503 - else: - status_code = 200 if patroni.ha.is_leader() else 503 + elif 'master' in path or 'leader' 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 + elif 'read-only' in path: + status_code = 200 if primary_status_code == 200 else replica_status_code elif cluster: # dcs is available is_synchronous = cluster.is_synchronous_mode() and cluster.sync \ and cluster.sync.sync_standby == patroni.postgresql.name