Class ManagedLeaderLatch

java.lang.Object
org.kiwiproject.curator.leader.ManagedLeaderLatch
All Implemented Interfaces:
io.dropwizard.lifecycle.Managed

public class ManagedLeaderLatch extends Object implements io.dropwizard.lifecycle.Managed
Wrapper around Curator's LeaderLatch which standardizes the id and latch path in ZooKeeper, and which registers with Dropwizard so that it manages the lifecycle (mainly to ensure the latch is stopped when the Dropwizard app stops).
Implementation Note:
Any methods that use hasLeadership() may result in a ManagedLeaderLatchException since that method can potentially throw one. See its documentation for the possible situations in which an exception could be thrown.
  • Constructor Details

    • ManagedLeaderLatch

      public ManagedLeaderLatch(org.apache.curator.framework.CuratorFramework client, ServiceDescriptor serviceDescriptor, org.apache.curator.framework.recipes.leader.LeaderLatchListener... listeners)
      Construct a latch with a standard ID and latch path.
      Parameters:
      client - the CuratorFramework client that this latch should use
      serviceDescriptor - service metadata
      listeners - zero or more LeaderLatchListener instances to attach to the leader latch
      Throws:
      IllegalArgumentException - if any arguments are null or blank
    • ManagedLeaderLatch

      public ManagedLeaderLatch(org.apache.curator.framework.CuratorFramework client, String id, String serviceName, org.apache.curator.framework.recipes.leader.LeaderLatchListener... listeners)
      Construct a latch with a specific ID and standard latch path.

      The serviceName should be the generic name of a service, e.g. "payment-service" or "order-service", instead of a unique service identifier.

      Parameters:
      client - the CuratorFramework client that this latch should use
      id - the unique ID for this latch instance
      serviceName - the generic name of the service, which ensures the same latch path is used for all instances of a given service
      listeners - zero or more LeaderLatchListener instances to attach to the leader latch
      Throws:
      IllegalArgumentException - if any arguments are null or blank
      See Also:
  • Method Details

    • leaderLatchId

      public static String leaderLatchId(ServiceDescriptor serviceDescriptor)
      Utility method to generate a standard latch id for a service.
      Parameters:
      serviceDescriptor - the service information to use
      Returns:
      a latch ID
    • leaderLatchId

      public static String leaderLatchId(String serviceName, String serviceVersion, String hostname, int port)
      Utility method to generate a standard latch id for a service.
      Parameters:
      serviceName - the name of the service
      serviceVersion - the version of the service
      hostname - the host name where the service instance is running
      port - the port on which the service instance is running
      Returns:
      a latch ID
    • leaderLatchPath

      public static String leaderLatchPath(String serviceName)
      Utility method to generate a standard latch path for a service.
      Parameters:
      serviceName - the name of the service
      Returns:
      the latch path for the given service
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • start

      public void start() throws Exception
      Starts the latch, possibly creating non-existent znodes in ZooKeeper first.

      The CuratorFramework must be started, or else a VerifyException will be thrown.

      This method will ignore repeated attempts to start once the latch has been started.

      Specified by:
      start in interface io.dropwizard.lifecycle.Managed
      Throws:
      com.google.common.base.VerifyException - if the CuratorFramework is not already started
      Exception
    • stop

      public void stop()
      Stops the latch. Any exceptions closing the latch are ignored, although they are logged.
      Specified by:
      stop in interface io.dropwizard.lifecycle.Managed
    • hasLeadership

      public boolean hasLeadership()
      Returns whether this instance is the leader, or throws a ManagedLeaderLatchException if Curator is not started yet, this latch is not started yet, or there are no latch participants yet.

      The above-mentioned situations could happen, for example, because code at startup calls this method before Curator has been started, e.g. before the Jetty server starts in a Dropwizard application, or because the latch does not yet have participants even though Curator and the latch are both started. These restrictions should help prevent false negatives, i.e. having a false return value but the actual reason was because of some other factor.

      Returns:
      true if this latch is currently the leader
      Throws:
      ManagedLeaderLatchException - if this method is called and any of the restrictions mentioned above apply
    • getParticipants

      public Collection<org.apache.curator.framework.recipes.leader.Participant> getParticipants()
      Get the participants (i.e. Dropwizard services) in this latch.
      Returns:
      unordered collection of leader latch participants
      Throws:
      ManagedLeaderLatchException - if any error occurs getting the participants
    • getLeader

      public org.apache.curator.framework.recipes.leader.Participant getLeader()
      Get the leader of this latch.
      Returns:
      the Participant who is the current leader
      Throws:
      ManagedLeaderLatchException - if any error occurs getting the leader
    • isStarted

      public boolean isStarted()
      Check if the latch is started.
      Returns:
      true if the latch state is LeaderLatch.State.STARTED
    • isClosed

      public boolean isClosed()
      Check if the latch is closed.
      Returns:
      true if the latch state is LeaderLatch.State.CLOSED
    • getLatchState

      public org.apache.curator.framework.recipes.leader.LeaderLatch.State getLatchState()
      Get the current latch state.
      Returns:
      the current LeaderLatch.State
    • whenLeader

      public void whenLeader(Runnable action)
      Perform the given action synchronously only if this latch is currently the leader. Use this when the action does not need to return a value and it is a "fire and forget" action.
      Parameters:
      action - the action to perform if this latch is the leader
    • whenLeaderAsync

      public Optional<CompletableFuture<Void>> whenLeaderAsync(Runnable action)
      Perform the given action asynchronously only if this latch is currently the leader. Use this when the action does not need to return a value and it is a "fire and forget" action. However, if the returned Optional is present, you can use the CompletableFuture to determine when the action has completed and take some other action, etc. if you want to.
      Parameters:
      action - the action to perform if this latch is the leader
      Returns:
      an Optional containing a CompletableFuture if this latch is the leader, otherwise an empty Optional
    • whenLeader

      public <T> Optional<T> whenLeader(Supplier<T> resultSupplier)
      Perform the given action defined by resultSupplier synchronously only if this latch is currently the leader, returning the result of resultSupplier.
      Type Parameters:
      T - the result type
      Parameters:
      resultSupplier - the result-returning action to perform if this latch is the leader
      Returns:
      an Optional containing the result if this latch is the leader, otherwise an empty Optional
    • whenLeaderAsync

      public <T> Optional<CompletableFuture<T>> whenLeaderAsync(Supplier<T> resultSupplier)
      Perform the given action defined by resultSupplier asynchronously only if this latch is currently the leader, returning a CompletableFuture whose result will be the result of the resultSupplier.
      Type Parameters:
      T - the result type
      Parameters:
      resultSupplier - the result-returning action to perform if this latch is the leader
      Returns:
      an Optional containing a CompletableFuture if this latch is the leader, otherwise an empty Optional
    • whenLeaderAsync

      public <T> Optional<CompletableFuture<T>> whenLeaderAsync(Supplier<T> resultSupplier, Executor executor)
      Same as whenLeaderAsync(Supplier) but uses supplied executor instead of CompletableFuture's default executor.
      Type Parameters:
      T - the result type
      Parameters:
      resultSupplier - the result-returning action to perform if this latch is the leader
      executor - the custom Executor to use
      Returns:
      an Optional containing a CompletableFuture if this latch is the leader, otherwise an empty Optional
    • getId

      public String getId()
    • getLatchPath

      public String getLatchPath()