Leader Election¶
Overview¶
Leader election lets you run several Workloads of the same Application at the edge, with only one of them acting at a time. If that Workload fails, another one takes over.
Without it, every Workload of an Application is a single point of failure. The kelvin.ha module in the Kelvin SDK does the election for you, so your code only asks "am I the leader?" and does not need its own polling or lease logic.
All the Workloads run the full Application. The one that is elected is the leader and does the work. The others are followers and wait to take over.
Note
Leader election is available to Applications and Import Applications, and it works at the edge, using the Leader Election API of the Cluster.
How It Works¶
- Each Workload checks in with the Leader Election API of its Cluster. The check-in is also the heartbeat that keeps the Workload in the election
- The API answers with who the leader is and for how long the lease lasts
- A Workload is the leader only while its lease has not expired
- The SDK does the check-ins in the background, about three times for each lease, so two missed requests do not cost the leadership
When to Use Leader Election¶
Use it when you run more than one Workload of the same Application for redundancy, and only one of them should publish, write or act at a time.
When a Workload is promoted, you can resume the work, for example resume publishing. When it is demoted, you can stop, for example drain a queue.
app.yaml Setup¶
There is nothing to declare in the app.yaml. The identity, the election and the address of the Leader Election API come from environment variables that the platform sets in your Workload. You do not need to declare or read them.
| Variable | Used for |
|---|---|
KELVIN_CLUSTER_NAME and KELVIN_WORKLOAD_NAME |
The identity of the Workload, krn:wl:<cluster>/<workload>. |
KELVIN_APP_NAME |
The default resource that the Workloads compete for, krn:app:<app>. |
KELVIN_LEADER_API_ADDRESS and KELVIN_LEADER_API_PORT |
The address of the Leader Election API of the Cluster. |
Deploy Time Setup¶
Deploy several Workloads of the same Application, as you do today. See Deploy Workload.
Python Example¶
Create a LeaderElection, start it, and do the work only while is_leader is True.
| Leader Election Python Example | |
|---|---|
- Check
is_leaderfor each unit of work. Do not store the result, because it can change at any time - Do not block the start of your Application waiting to be the leader. Every Workload runs the full Application, so a follower can take over straight away
Note
Outside of a Kelvin Workload the environment variables are missing. Nothing fails. A warning is logged, start() does nothing and is_leader stays False.
asyncio Applications¶
AsyncLeaderElection has the same options as a task on your event loop. You await its start() and stop().
To wait until the Workload is the leader, use await leader.wait_until_leader().
Promotion and Demotion¶
Use the on_promoted and on_demoted hooks to do something when the Workload becomes the leader or stops being the leader, for example to resume publishing or to drain a queue.
You can set them by assigning a function.
| Hooks by Assignment Python Example | |
|---|---|
Or with decorators.
| Hooks by Decorator Python Example | |
|---|---|
- The hooks fire only when the state changes. A lease renewal does not fire
on_promotedagain - If a hook raises an error, the error is logged and the election continues
LeaderElectionaccepts normal functions only. Anasync defis logged as an error and is not runAsyncLeaderElectionaccepts normal and async functions, with decorators or by assignment
| Async Hooks Python Example | |
|---|---|
Scope¶
By default, all the Workloads of an Application compete for the same leadership, the Application itself, krn:app:<app>.
If the default is not right, pass another resource. For example, to let different versions of an Application, such as blue and green, elect their leaders independently:
| Scoped Leader Election Python Example | |
|---|---|
The resource must be a KRN. See the KRN reference.
Current Leader¶
current_leader shows who the leader is, even when it is not you. A follower can use it to log or show which Workload is active.
| Current Leader Python Example | |
|---|---|
It keeps the last leader it saw. It is not cleared when the Workload is demoted or stopped.
Failover Behavior¶
- Lost connection: If the Application cannot reach the Leader Election API,
is_leaderbecomesFalseas soon as the lease expires, even if the API never said the Workload was demoted. An isolated Workload is demoted within one lease duration, and the API promotes a Workload that it can reach - Stopping:
stop()demotes the Workload straight away and fireson_demoted, so another Workload takes over within the lease duration. Always callstop()when your Application shuts down. Without it, the Workload keeps its lease until it expires and the takeover is delayed
Warning
Leadership is advisory. On the edges of a network partition, two Workloads can both think they are the leader for a short time. Between one lease ending and the next promotion, there can also be a short time with no leader.
If your Application does critical writes, add protection downstream against repeated or out of order writes. is_leader is not a lock.
Example: Publish From One Workload Only¶
An Application publishes a value every 5 seconds. You deploy two Workloads of it for redundancy. Only the leader publishes, and the other one waits.
Both Workloads declare the same outputs in the app.yaml. If the leader stops, the other Workload is promoted within the lease duration and starts publishing.
Leader Election Reference¶
| Member | Description |
|---|---|
LeaderElection(resource=None) and AsyncLeaderElection(resource=None) |
Creates the election. The resource is optional and must be a KRN. The default is krn:app:<app>. |
start() |
Starts the check-ins in the background. Nothing happens if it is already running. AsyncLeaderElection must be awaited. |
stop() |
Stops the check-ins and demotes the Workload straight away. on_demoted fires if it was the leader. |
is_leader |
True only while the last answer confirmed the leadership and the lease has not expired. |
wait_until_leader(timeout=None) |
Waits until the Workload is the leader. Returns False if the timeout is reached. Without a timeout it waits without limit. |
current_leader |
The last leader that was seen. |
on_promoted and on_demoted |
The hooks, set by decorator or by assignment. |