Last active
April 13, 2023 07:28
-
-
Save tfrench/3ee209f1d533dc73a7e63298177a02d9 to your computer and use it in GitHub Desktop.
etcd v3 leader election using Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""etcd3 Leader election.""" | |
import sys | |
import time | |
from threading import Event | |
import etcd3 | |
LEADER_KEY = '/leader' | |
LEASE_TTL = 5 | |
SLEEP = 1 | |
def put_not_exist(client, key, value, lease=None): | |
status, _ = client.transaction( | |
compare=[ | |
client.transactions.version(key) == 0 | |
], | |
success=[ | |
client.transactions.put(key, value, lease) | |
], | |
failure=[], | |
) | |
return status | |
def leader_election(client, me): | |
try: | |
lease = client.lease(LEASE_TTL) | |
status = put_not_exist(client, LEADER_KEY, me, lease) | |
except Exception: | |
status = False | |
return status, lease | |
def main(me): | |
client = etcd3.client(timeout=2) | |
while True: | |
print('leader election') | |
leader, lease = leader_election(client, me) | |
if leader: | |
print('leader') | |
try: | |
while True: | |
# do work | |
lease.refresh() | |
time.sleep(SLEEP) | |
except (Exception, KeyboardInterrupt): | |
return | |
finally: | |
lease.revoke() | |
else: | |
print('follower; standby') | |
election_event = Event() | |
def watch_cb(event): | |
if isinstance(event, etcd3.events.DeleteEvent): | |
election_event.set() | |
watch_id = client.add_watch_callback(LEADER_KEY, watch_cb) | |
try: | |
while not election_event.is_set(): | |
time.sleep(SLEEP) | |
print('new election') | |
except (Exception, KeyboardInterrupt): | |
return | |
finally: | |
client.cancel_watch(watch_id) | |
if __name__ == '__main__': | |
me = sys.argv[1] | |
main(me) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
watch_cb does not seem to work properly from my tests
If leader is killed, nothing happens on the followers
You need to adjust the watch_cb using this condition:
if isinstance(event, etcd3.events.DeleteEvent) or isinstance(event, etcd3.watch.WatchResponse):