mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-25 14:53:37 +00:00
make healthiest node work
This commit is contained in:
+14
-6
@@ -37,12 +37,6 @@ class Etcd:
|
|||||||
def client_url(self, path):
|
def client_url(self, path):
|
||||||
return "http://%s/v2/keys/service/%s%s" % (self.host, self.scope, path)
|
return "http://%s/v2/keys/service/%s%s" % (self.host, self.scope, path)
|
||||||
|
|
||||||
def xlog_position(member):
|
|
||||||
try:
|
|
||||||
return self.get_client_path("/service/postgresql/xlog-position/%s" % member)["node"]["value"]
|
|
||||||
except urllib2.HTTPError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def current_leader(self):
|
def current_leader(self):
|
||||||
try:
|
try:
|
||||||
hostname = self.get_client_path("/leader")["node"]["value"]
|
hostname = self.get_client_path("/leader")["node"]["value"]
|
||||||
@@ -54,6 +48,20 @@ class Etcd:
|
|||||||
return None
|
return None
|
||||||
raise helpers.errors.CurrentLeaderError("Etcd is not responding properly")
|
raise helpers.errors.CurrentLeaderError("Etcd is not responding properly")
|
||||||
|
|
||||||
|
def members(self):
|
||||||
|
try:
|
||||||
|
members = []
|
||||||
|
|
||||||
|
r = self.get_client_path("/members?recursive=true")
|
||||||
|
for node in r["node"]["nodes"]:
|
||||||
|
members.append({"hostname": node["key"].split('/')[-1], "address": node["value"]})
|
||||||
|
|
||||||
|
return members
|
||||||
|
except urllib2.HTTPError as e:
|
||||||
|
if e.code == 404:
|
||||||
|
return None
|
||||||
|
raise helpers.errors.CurrentLeaderError("Etcd is not responding properly")
|
||||||
|
|
||||||
def touch_member(self, member, connection_string):
|
def touch_member(self, member, connection_string):
|
||||||
self.put_client_path("/members/%s" % member, {"value": connection_string})
|
self.put_client_path("/members/%s" % member, {"value": connection_string})
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ class Ha:
|
|||||||
try:
|
try:
|
||||||
if self.state_handler.is_healthy():
|
if self.state_handler.is_healthy():
|
||||||
if self.is_unlocked():
|
if self.is_unlocked():
|
||||||
if self.state_handler.is_healthiest_node():
|
if self.state_handler.is_healthiest_node(self.etcd.members()):
|
||||||
if self.acquire_lock():
|
if self.acquire_lock():
|
||||||
if not self.state_handler.is_leader():
|
if not self.state_handler.is_leader():
|
||||||
self.state_handler.promote()
|
self.state_handler.promote()
|
||||||
|
|||||||
+20
-1
@@ -104,7 +104,23 @@ class Postgresql:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def is_healthiest_node(self):
|
def is_healthiest_node(self, members):
|
||||||
|
for member in members:
|
||||||
|
if member["hostname"] == self.name:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
member_conn = psycopg2.connect(member["address"])
|
||||||
|
member_conn.autocommit = True
|
||||||
|
member_cursor = member_conn.cursor()
|
||||||
|
member_cursor.execute("SELECT '%s'::pg_lsn - pg_last_xlog_replay_location() AS bytes;" % self.xlog_position())
|
||||||
|
xlog_diff = member_cursor.fetchone()[0]
|
||||||
|
print [self.name, member["hostname"], xlog_diff]
|
||||||
|
if xlog_diff < 0:
|
||||||
|
member_cursor.close()
|
||||||
|
return False
|
||||||
|
member_cursor.close()
|
||||||
|
except psycopg2.OperationalError:
|
||||||
|
continue
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def replication_slot_name(self):
|
def replication_slot_name(self):
|
||||||
@@ -150,3 +166,6 @@ recovery_target_timeline = 'latest'
|
|||||||
|
|
||||||
def create_replication_user(self):
|
def create_replication_user(self):
|
||||||
self.query("CREATE USER \"%s\" WITH REPLICATION ENCRYPTED PASSWORD '%s';" % (self.replication["username"], self.replication["password"]))
|
self.query("CREATE USER \"%s\" WITH REPLICATION ENCRYPTED PASSWORD '%s';" % (self.replication["username"], self.replication["password"]))
|
||||||
|
|
||||||
|
def xlog_position(self):
|
||||||
|
return self.query("SELECT pg_last_xlog_replay_location();").fetchone()[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user