Interface ElectionService

  • All Superinterfaces:
    Service

    @DefaultServiceFactory(ElectionServiceFactory.class)
    public interface ElectionService
    extends Service
    « start hereMain entry point to leader election API.

    Overview

    This service provides support for electing a leader among a set of cluster nodes that belong to the same election group. This service guarantees that only one node within each group will be elected as a leader and all other nodes will become followers. If leader node goes down or decides to yield its leadership then some other node will be elected as a new leader.

    In order to participate in leader election process, each node must register an implementation of the Candidate interface and specify its group name. Each node can register candidates to multiple groups and ElectionService will make sure that only one node within each group will become a leader.

    Service Configuration

    ElectionService can be registered and configured in HekateBootstrap with the help of ElectionServiceFactory as shown in the example below:

    
    // Prepare service factory.
    ElectionServiceFactory factory = new ElectionServiceFactory()
        // Register candidate.
        .withCandidate(new CandidateConfig()
            // Group name.
            .withGroup("example.election.group")
            // Candidate implementation.
            .withCandidate(new ExampleCandidate())
        );
    
    // Start node.
    Hekate hekate = new HekateBootstrap()
        .withService(factory)
        .join();
    
    // Access the service.
    ElectionService election = hekate.election();
    
    Note: This example requires Spring Framework integration (see HekateSpringBootstrap).
    
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:h="http://www.hekate.io/spring/hekate-core"
        xmlns="http://www.springframework.org/schema/beans"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.hekate.io/spring/hekate-core
            http://www.hekate.io/spring/hekate-core.xsd">
    
        <h:node id="hekate">
            <!-- Leader election service. -->
            <h:election>
                <!-- Register leader election candidate. -->
                <h:candidate group="example.election.group">
                    <bean class="foo.bar.SomeCandidate"/>
                </h:candidate>
            </h:election>
    
            <!-- ...other services... -->
        </h:node>
    </beans>
    
    Note: This example requires Spring Framework integration (see HekateSpringBootstrap).
    
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="hekate" class="io.hekate.spring.bean.HekateSpringBootstrap">
            <property name="services">
                <list>
                    <!-- Leader election service. -->
                    <bean class="io.hekate.election.ElectionServiceFactory">
                        <property name="candidates">
                            <list>
                                <!-- Register leader election candidate. -->
                                <bean class="io.hekate.election.CandidateConfig">
                                    <property name="group" value="example.election.group"/>
                                    <property name="candidate">
                                        <bean class="foo.bar.SomeCandidate"/>
                                    </property>
                                </bean>
                            </list>
                        </property>
                    </bean>
    
                    <!-- ...other services... -->
                </list>
            </property>
        </bean>
    </beans>
    

    Leader Election

    Leader election process starts right after the node joins the cluster. If leader has been already elected by that time then Candidate switches to the folower state. If this is the first node in the election group then Candidate switches to the leader state. If multiple nodes are joining the cluster at the same time then only one of them will be elected as a leader and all other nodes will switch to the follower state.

    If Candidate won elections and became a group leader then it will remain in this state until its cluster node is stopped or until it yields its leadership by calling LeaderContext.yieldLeadership(). In the first case some other node will be elected as a new leader and will be notified via Candidate.becomeLeader(LeaderContext) method. In the second case leadership will be withdrawn and with high probability some other node will become a new leader. If no other node could win elections then the same node will become leader again and its Candidate.becomeLeader(LeaderContext) method will be called.

    When Candidate switches to the follower state then it can optionally register a leader change listener via FollowerContext.addListener(LeaderChangeListener). This listener will be notified every time when leadership gets transferred from one remote node to another remote node.

    Below is the example of Candidate interface implementation:

    
    class ExampleCandidate implements Candidate {
        @Override
        public void becomeLeader(LeaderContext ctx) {
            System.out.println("I'm leader.");
    
            // ...do some work as leader...
    
            System.out.println("Done with the leader task ...will yield leadership.");
    
            // Let some other node to become a leader.
            ctx.yieldLeadership();
        }
    
        @Override
        public void becomeFollower(FollowerContext ctx) {
            System.out.println("Leader: " + ctx.leader());
    
            // Listen for leader change events while we are staying in the follower state.
            ctx.addListener(changed ->
                System.out.println("Leader changed: " + changed.leader())
            );
        }
    
        @Override
        public void terminate() {
            // ...cleanup logic...
        }
    }
    

    Leader Election Details

    Leader elections are based on the LockService capabilities. During the startup ElectionService tries to asynchronously acquire a distributed lock for each of its registered groups. If lock acquisition is successful then Candidate of such group gets notified on becoming a leader. If lock is busy then Candidate get notified on becoming a follower and continues to await for the lock to be acquired.

    See Also:
    ElectionServiceFactory