From b4e86f080990368a931fefa56a62ec35ae3891d6 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Wed, 13 Apr 2016 11:00:32 +0200 Subject: [PATCH] Make it possible to schedule failover in less then 10 seconds But only when API request was posted to the leader --- features/patroni_api.feature | 2 +- patroni/api.py | 12 ++++++++---- tests/test_api.py | 3 +++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/features/patroni_api.feature b/features/patroni_api.feature index 75d44304..9216343e 100644 --- a/features/patroni_api.feature +++ b/features/patroni_api.feature @@ -44,7 +44,7 @@ Scenario: check the failover via the API And replication works from postgres1 to postgres0 after 15 seconds Scenario: check the scheduled failover - Given I issue a scheduled failover at http://127.0.0.1:8009 from postgres1 to postgres0 in 10 seconds + Given I issue a scheduled failover at http://127.0.0.1:8009 from postgres1 to postgres0 in 1 seconds Then I receive a response code 200 And postgres0 is a leader after 20 seconds And postgres0 role is the primary after 5 seconds diff --git a/patroni/api.py b/patroni/api.py index 2ae66e40..725faf0f 100644 --- a/patroni/api.py +++ b/patroni/api.py @@ -203,8 +203,12 @@ class RestApiHandler(BaseHTTPRequestHandler): data = b'Cannot schedule failover in the past' status_code = 422 elif self.server.patroni.dcs.manual_failover(leader, candidate, scheduled_at=scheduled_at): + self.server.patroni.dcs.event.set() data = b'Failover scheduled' status_code = 200 + else: + data = b'failed to write failover key into DCS' + status_code = 503 except (ValueError, TypeError): logger.exception('Invalid scheduled failover time: %s', request['scheduled_at']) data = b'Unable to parse scheduled timestamp. It should be in an unambiguous format, e.g. ISO 8601' @@ -212,12 +216,12 @@ class RestApiHandler(BaseHTTPRequestHandler): else: data = self.is_failover_possible(cluster, leader, candidate) if not data: - if not self.server.patroni.dcs.manual_failover(leader, candidate): - data = b'failed to write failover key into DCS' - status_code = 503 - else: + if self.server.patroni.dcs.manual_failover(leader, candidate): self.server.patroni.dcs.event.set() status_code, data = self.poll_failover_result(cluster.leader and cluster.leader.name, candidate) + else: + data = b'failed to write failover key into DCS' + status_code = 503 else: status_code = 400 data = b'No values given for required parameters leader and candidate' diff --git a/tests/test_api.py b/tests/test_api.py index 1a3d00ce..5b31104e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -188,6 +188,9 @@ class TestRestApiHandler(unittest.TestCase): request = b'POST /failover HTTP/1.0\nAuthorization: Basic dGVzdDp0ZXN0\nContent-Length: 103\n\n{"leader": ' +\ b'"postgresql1", "member": "postgresql2", "scheduled_at": "6016-02-15T18:13:30.568224+01:00"}' MockRestApiServer(RestApiHandler, request) + with patch.object(MockPatroni, 'dcs') as d: + d.manual_failover.return_value = False + MockRestApiServer(RestApiHandler, request) # Exception: No timezone specified request = b'POST /failover HTTP/1.0\nAuthorization: Basic dGVzdDp0ZXN0\nContent-Length: 97\n\n{"leader": ' +\