Class 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 Detail

      • 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:
        leaderLatchPath(String)
    • Method Detail

      • 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
      • 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