---
title: Leader Election
category: Behavioral
language: en
tag:
- Cloud distributed
---
## Intent
Leader Election pattern is commonly used in cloud system design. It can help to ensure that task
instances select the leader instance correctly and do not conflict with each other, cause
contention for shared resources, or inadvertently interfere with the work that other task
instances are performing.
## Explanation
Real world example
> In a horizontally scaling cloud-based system, multiple instances of the same task could be
> running at the same time with each instance serving a different user. If these instances
> write to a shared resource, it's necessary to coordinate their actions to prevent each instance
> from overwriting the changes made by the others. In another scenario, if the tasks are performing
> individual elements of a complex calculation in parallel, the results need to be aggregated
> when they all complete.
In plain words
> this pattern is used in distributed cloud-based system where leader must need to act as
> coordinator/aggregator among horizontal scaling instances for avoiding conflict on shared resources.
Wikipedia says
> In distributed computing, leader election is the process of designating a single process as
> the organizer of some task distributed among several computers (nodes).
**Programmatic Example**
Ring algorithm and Bully algorithm implement leader election pattern.
Each algorithm require every participated instance to have unique ID.
```java
public interface Instance {
/**
* Check if the instance is alive or not.
*
* @return {@code true} if the instance is alive.
*/
boolean isAlive();
/**
* Set the health status of the certain instance.
*
* @param alive {@code true} for alive.
*/
void setAlive(boolean alive);
/**
* Consume messages from other instances.
*
* @param message Message sent by other instances
*/
void onMessage(Message message);
}
```
Abstract class who implements Instance and Runnable interfaces.
```java
public abstract class AbstractInstance implements Instance, Runnable {
protected static final int HEARTBEAT_INTERVAL = 5000;
private static final String INSTANCE = "Instance ";
protected MessageManager messageManager;
protected Queue<Message> messageQueue;
protected final int localId;
protected int leaderId;
protected boolean alive;
/**
* Constructor of BullyInstance.
*/
public AbstractInstance(MessageManager messageManager, int localId, int leaderId) {
this.messageManager = messageManager;
this.messageQueue = new ConcurrentLinkedQueue<>();
this.localId = localId;
this.leaderId = leaderId;
this.alive = true;
}
/**
* The instance will execute the message in its message queue periodically once it is alive.
*/
@Override
@SuppressWarnings("squid:S2189")
public void run() {
while (true) {
if (!this.messageQueue.isEmpty()) {
this.processMessage(this.messageQueue.remove());
}
}
}
/**
* Once messages are sent to the certain instance, it will firstly be added to the queue and wait
* to be executed.
*
* @param message Message sent by other instances
*/
@Override
public void onMessage(Message message) {
messageQueue.offer(message);
}
/**
* Check if the instance is alive or not.
*
* @return {@code true} if the instance is alive.
*/
@Override
public boolean isAlive() {
return alive;
}
/**
* Set the health status of the certain instance.
*
* @param alive {@code true} for alive.
*/
@Override
public void setAlive(boolean alive) {
this.alive = alive;
}
/**
* Process the message according to its type.
*
* @param message Message polled from queue.
*/
private void processMessage(Message message) {
switch (message.getType()) {
case ELECTION -> {
LOGGER.info(INSTANCE + localId + " - Election Message handling...");
handleElectionMessage(message);
}
case LEADER -> {
LOGGER.info(INSTANCE + localId + " - Leader Message handling...");
handleLeaderMessage(message);
}
case HEARTBEAT -> {
LOGGER.info(INSTANCE + localId + " - Heartbeat Message handling...");
handleHeartbeatMessage(message);
}
case ELECTION_INVOKE -> {
LOGGER.info(INSTANCE + localId + " - Election Invoke Message handling...");
handleElectionInvokeMessage();
}
case LEADER_INVOKE -> {
LOGGER.info(INSTANCE + localId + " - Leader Invoke Message handling...");
handleLeaderInvokeMessage();
}
case HEARTBEAT_INVOKE -> {
LOGGER.info(INSTANCE + localId + " - Heartbeat Invoke Message handling...");
handleHeartbeatInvokeMessage();
}
default -> {
}
}
}
/**
* Abstract methods to handle different types of message. These methods need to be implemented in
* concrete instance class to implement corresponding leader-selection pattern.
*/
protected abstract void handleElectionMessage(Message message);
protected abstract void handleElectionInvokeMessage();
protected abstract void handleLeaderMessage(Message message);
protected abstract void handleLeaderInvokeMessage();
protected abstract void handleHeartbeatMessage(Message message);
protected abstract void handleHeartbeatInvokeMessage();
}
```
```java
/**
* Message used to transport data between instances.
*/
@Setter
@Getter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class Message {
private MessageType type;
private String content;
}
```
```java
public interface MessageManager {
/**
* Send heartbeat message to leader instance to check whether the leader instance is alive.
*
* @param leaderId Instance ID of leader instance.
* @return {@code true} if leader instance is alive, or {@code false} if not.
*/
boolean sendHeartbeatMessage(int leaderId);
/**
* Send election message to other instances.
*
* @param currentId Instance ID of which sends this message.
* @param content Election message content.
* @return {@code true} if the message is accepted by the target instances.
*/
boolean sendElectionMessage(int currentId, String content);
/**
* Send new leader notification message to other instances.
*
* @param currentId Instance ID of which sends this message.
* @param leaderId Leader message content.
* @return {@code true} if the message is accepted by the target instances.
*/
boolean sendLeaderMessage(int currentId, int leaderId);
/**
* Send heartbeat invoke message. This will invoke heartbeat task in the target instance.
*
* @param currentId Instance ID of which sends this message.
*/
void sendHeartbeatInvokeMessage(int currentId);
}
```
These type of messages are used to pass among instances.
```java
/**
* Message Type enum.
*/
public enum MessageType {
/**
* Start the election. The content of the message stores ID(s) of the candidate instance(s).
*/
ELECTION,
/**
* Nodify the new leader. The content of the message should be the leader ID.
*/
LEADER,
/**
* Check health of current leader instance.
*/
HEARTBEAT,
/**
* Inform target instance to start election.
*/
ELECTION_INVOKE,
/**
* Inform target instance to notify all the other instance that it is the new leader.
*/
LEADER_INVOKE,
/**
* Inform target instance to start heartbeat.
*/
HEARTBEAT_INVOKE
}
```
Abstract class who implements MessageManager interface. It helps to manage messages among instance.
```java
/**
* Abstract class of all the message manager classes.
*/
public abstract class AbstractMessageManager implements MessageManager {
/**
* Contain all the instances in the system. Key is its ID, and value is the instance itself.
*/
protected Map<Integer, Instance> instanceMap;
/**
* Constructor of AbstractMes