Giter Site home page Giter Site logo

spring-solace-leader-election's Introduction

Contributor Covenant

Leader election for spring integration with solace

This starter provides leader election based on solace exclusive queues.

Use cases

A consumer group wants to schedule tasks

Only one member of your consumer group should run the scheduled task.

You have a service/component with the spring standard @Scheduled annotation, as well as the @LeaderAware annotation, that suppresses the method execution if you are not leader of the example group "demo".

@Service
public class MyScheduledService {

    @Scheduled(fixedRateString = "PT3S", initialDelayString = "PT1S")
    @LeaderAware("demo")
    void scheduler() {
        log.info("I am the leader and log it schedules all 3s");
    }
}

The @LeaderAware annotation can be used on any component method. Those methods will return null if the code was not executed. You need to specify in your application.yaml to auto join the group whenever your application is ready.

spring:
  leader:
    join-groups:
      - groupName: demo
        joinType: ON_READINESS

Having leader group name in configuration

if your not want to have the leader group name in your configuration. You could do:

@Service
public class MyScheduledService {

    @Scheduled(fixedRateString = "PT3S", initialDelayString = "PT1S")
    @LeaderAware(configValue = "application.name")
    void scheduler() {
        log.info("I am the leader and log it schedules all 3s");
    }
}
application:
  name: DemoApp

spring:
  leader:
    join-groups:
      - groupName: DemoApp
        joinType: ON_READINESS

Execute business logic on leader events

When listening to leader based events, you will receive OnGrantedEvent and OnRevokedEvent events.
You can query the leader role via event.getRole() or use the condition = "#leaderEvent.role == 'demo'" option of the @EventListener to receive events only for a single leader group.

This requires the join-groups configuration set to "ON_READINESS".

    @EventListener(classes = {AbstractLeaderEvent.class}, condition = "#leaderEvent.role == 'demo'")
    void leaderEventListener(AbstractLeaderEvent leaderEvent)  {
        log.warn("LeaderController: " + leaderEvent);
    }

Test for leadership within business logic

You can test whether you are the leader in your business logic and decide what you want to do with this information.

@Autowired
private SolaceLeaderInitiator leaderInitiator;

private void yourLeaderMethod() {
    boolean isLeader = leaderInitiator.getContext("theNameOfTheRoleC").isLeader();
    if (isLeader) {
    	// ...
    }
    return;
}

Yield the leadership - "local process (debugging)"

In case you have a cluster of leader services you may want to hand over the leadership to a local process. The leadership can not be taken but must be handed over to a new process, which joined the cluster. The order of leadership is based on the time a process joined the group. When a process X currently owns the leadership and wants to yield it, the next leader process will be the process, which joined the group right after process X.

@GetMapping(value = "/leader/yield/{role}")
public String yieldLeaderShip(@PathVariable("role") final String role) {
    Context context = leaderInitiator.getContext(role);
    if (context.isLeader()) {
        context.yield();
        return context.isLeader() ? "I am leader AGAIN! Am I the only group member?" : "I am not longer the leader";
    }
    return "I was not the leader";
}

Yield the leadership - at shutdown

By default, the leadership will be yielded on shutdown. To improve the failover speed. Because on a grace full application shut down. Tear down broker connection, database connection can take up to 1sec.

But if there is a reason that stops you from using this feature you can disable this by:

spring:
  leader:
    join-groups:
      - groupName: DemoApp
        joinType: ON_READINESS
        yieldOnShutdown: false

or if you join groups programmatically:

@Autowired
private SolaceLeaderInitiator leaderInitiator;

private void yourMethode() {
    leaderInitiator.joinGroup("theNameOfTheRoleA", false);
}

Requirement

Just add this to your pom.xml file:

        <dependency>
            <groupId>community.solace.spring.integration</groupId>
            <artifactId>solace-spring-integration-leader</artifactId>
            <version>1.2.0</version>
        </dependency>

Config

join-groups

There are three different options to join a group:

  • programmatically: explicitly invoke a method to join a group
  • during the first request of the leader context
  • as soon as your application is ready

Join methods are appended to the leader group name below the "join-groups" configuration key:

spring:
  leader:
    join-groups:
      - groupName: theNameOfTheRoleA
        joinType: PROGRAMMATIC
      - groupName: theNameOfTheRoleB
        joinType: PROGRAMMATIC
      - groupName: theNameOfTheRoleC
        joinType: FIRST_USE
      - groupName: demo
        joinType: ON_READINESS

Join group PROGRAMMATIC

@Autowired
private SolaceLeaderInitiator leaderInitiator;

private void yourMethode() {
    leaderInitiator.joinGroup("theNameOfTheRoleA");
}

By default, also those groups has to be defined in your application configuration.
You can allow anonymous PROGRAMMATIC stated groups by setting:

spring:
  leader:
    permit-anonymous-groups: true

⚠️ Be aware of the side effect, to be able to join groups via JMX you may not want to be joined from this application.

Join group FIRST_USE

The leader group will be joined when you request the leader context for the first time.

@Autowired
private SolaceLeaderInitiator leaderInitiator;

@GetMapping(value = "/leader/status/{role}")
public String isLeader(@PathVariable("role") final String role) {
    return leaderInitiator.getContext(role).isLeader() ? "leader" : "passive";
}

Join group ON_READINESS

The leader group will be joined as soon as your application is ready. This allows to run bootstrap code like cache loading via ApplicationRunner This is useful in combination with the @LeaderAware annotation.

Solace specifics

Queues

A durable Solace queue is provisioned for each leader group. The queue name is "leader." + role. A queue is exclusively used for the flow activation trigger. No other messages are supposed to pass this queue. Any other message apart from the flow activation trigger will lead to an exception.

⚠️ The Solace ClientProfile must have "Allow client to create endpoints" set to true

Timeout

The fail over timeout is managed by the solace ClientProfile. (Broker version >= 9.7)

broker# show client smf1 detail 
Client Keepalive:
  Enabled:                    Yes
  Effective Timeout (sec):    10
broker> enable
broker# configure 
broker(configure)# client-profile default message-vpn default 
broker(configure/client-profile)# service 
broker(configure/client-profile/service)# min-keepalive-timeout 10 
broker(configure/client-profile/service)# smf 
broker(configure/client-profile/service/smf)# min-keepalive-enabled 
broker> show client-profile default message-vpn default detail 
  Client Keepalive 
    Enabled for SMF clients             : Yes 
    Minimum Timeout                     : 10    seconds 

JMX integration

This starter provides some JMX operations to remote manage the application leadership.

JMX sample actions

JMS sample operations

Micrometer integration

For monitoring purpose we provide a micrometer metrics.

Here an example if your application uses the micrometer-prometheus-registry.

# HELP leader_status Indicates if this project is [-1=not joined, 0=joined but not leader, 1=is leader] for a group.
# TYPE leader_status gauge
leader_status{group="noJoined",} -1.0
leader_status{group="theOther",} 0.0
leader_status{group="demo",} 1.0 

Resources

For more information try these resources:

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Authors

See the list of contributors who participated in this project.

License

See the LICENSE file for details.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.