• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.util.concurrent;
16 
17 import com.google.common.annotations.GwtIncompatible;
18 import com.google.errorprone.annotations.CanIgnoreReturnValue;
19 import com.google.errorprone.annotations.DoNotMock;
20 import java.util.concurrent.Executor;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23 
24 /**
25  * An object with an operational state, plus asynchronous {@link #startAsync()} and {@link
26  * #stopAsync()} lifecycle methods to transition between states. Example services include
27  * webservers, RPC servers and timers.
28  *
29  * <p>The normal lifecycle of a service is:
30  *
31  * <ul>
32  *   <li>{@linkplain State#NEW NEW} -&gt;
33  *   <li>{@linkplain State#STARTING STARTING} -&gt;
34  *   <li>{@linkplain State#RUNNING RUNNING} -&gt;
35  *   <li>{@linkplain State#STOPPING STOPPING} -&gt;
36  *   <li>{@linkplain State#TERMINATED TERMINATED}
37  * </ul>
38  *
39  * <p>There are deviations from this if there are failures or if {@link Service#stopAsync} is called
40  * before the {@link Service} reaches the {@linkplain State#RUNNING RUNNING} state. The set of legal
41  * transitions form a <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>,
42  * therefore every method of the listener will be called at most once. N.B. The {@link State#FAILED}
43  * and {@link State#TERMINATED} states are terminal states, once a service enters either of these
44  * states it cannot ever leave them.
45  *
46  * <p>Implementors of this interface are strongly encouraged to extend one of the abstract classes
47  * in this package which implement this interface and make the threading and state management
48  * easier.
49  *
50  * @author Jesse Wilson
51  * @author Luke Sandberg
52  * @since 9.0 (in 1.0 as {@code com.google.common.base.Service})
53  */
54 @DoNotMock("Create an AbstractIdleService")
55 @GwtIncompatible
56 @ElementTypesAreNonnullByDefault
57 public interface Service {
58   /**
59    * If the service state is {@link State#NEW}, this initiates service startup and returns
60    * immediately. A stopped service may not be restarted.
61    *
62    * @return this
63    * @throws IllegalStateException if the service is not {@link State#NEW}
64    * @since 15.0
65    */
66   @CanIgnoreReturnValue
startAsync()67   Service startAsync();
68 
69   /** Returns {@code true} if this service is {@linkplain State#RUNNING running}. */
isRunning()70   boolean isRunning();
71 
72   /** Returns the lifecycle state of the service. */
state()73   State state();
74 
75   /**
76    * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running},
77    * this initiates service shutdown and returns immediately. If the service is {@linkplain
78    * State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been started nor
79    * stopped. If the service has already been stopped, this method returns immediately without
80    * taking action.
81    *
82    * @return this
83    * @since 15.0
84    */
85   @CanIgnoreReturnValue
stopAsync()86   Service stopAsync();
87 
88   /**
89    * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state}.
90    *
91    * @throws IllegalStateException if the service reaches a state from which it is not possible to
92    *     enter the {@link State#RUNNING} state. e.g. if the {@code state} is {@code
93    *     State#TERMINATED} when this method is called then this will throw an IllegalStateException.
94    * @since 15.0
95    */
awaitRunning()96   void awaitRunning();
97 
98   /**
99    * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state} for no more
100    * than the given time.
101    *
102    * @param timeout the maximum time to wait
103    * @param unit the time unit of the timeout argument
104    * @throws TimeoutException if the service has not reached the given state within the deadline
105    * @throws IllegalStateException if the service reaches a state from which it is not possible to
106    *     enter the {@link State#RUNNING RUNNING} state. e.g. if the {@code state} is {@code
107    *     State#TERMINATED} when this method is called then this will throw an IllegalStateException.
108    * @since 15.0
109    */
110   @SuppressWarnings("GoodTime") // should accept a java.time.Duration
awaitRunning(long timeout, TimeUnit unit)111   void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException;
112 
113   /**
114    * Waits for the {@link Service} to reach the {@linkplain State#TERMINATED terminated state}.
115    *
116    * @throws IllegalStateException if the service {@linkplain State#FAILED fails}.
117    * @since 15.0
118    */
awaitTerminated()119   void awaitTerminated();
120 
121   /**
122    * Waits for the {@link Service} to reach a terminal state (either {@link Service.State#TERMINATED
123    * terminated} or {@link Service.State#FAILED failed}) for no more than the given time.
124    *
125    * @param timeout the maximum time to wait
126    * @param unit the time unit of the timeout argument
127    * @throws TimeoutException if the service has not reached the given state within the deadline
128    * @throws IllegalStateException if the service {@linkplain State#FAILED fails}.
129    * @since 15.0
130    */
131   @SuppressWarnings("GoodTime") // should accept a java.time.Duration
awaitTerminated(long timeout, TimeUnit unit)132   void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException;
133 
134   /**
135    * Returns the {@link Throwable} that caused this service to fail.
136    *
137    * @throws IllegalStateException if this service's state isn't {@linkplain State#FAILED FAILED}.
138    * @since 14.0
139    */
failureCause()140   Throwable failureCause();
141 
142   /**
143    * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given
144    * executor. The listener will have the corresponding transition method called whenever the
145    * service changes state. The listener will not have previous state changes replayed, so it is
146    * suggested that listeners are added before the service starts.
147    *
148    * <p>{@code addListener} guarantees execution ordering across calls to a given listener but not
149    * across calls to multiple listeners. Specifically, a given listener will have its callbacks
150    * invoked in the same order as the underlying service enters those states. Additionally, at most
151    * one of the listener's callbacks will execute at once. However, multiple listeners' callbacks
152    * may execute concurrently, and listeners may execute in an order different from the one in which
153    * they were registered.
154    *
155    * <p>RuntimeExceptions thrown by a listener will be caught and logged. Any exception thrown
156    * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException}) will be caught and
157    * logged.
158    *
159    * @param listener the listener to run when the service changes state is complete
160    * @param executor the executor in which the listeners callback methods will be run. For fast,
161    *     lightweight listeners that would be safe to execute in any thread, consider {@link
162    *     MoreExecutors#directExecutor}.
163    * @since 13.0
164    */
addListener(Listener listener, Executor executor)165   void addListener(Listener listener, Executor executor);
166 
167   /**
168    * The lifecycle states of a service.
169    *
170    * <p>The ordering of the {@link State} enum is defined such that if there is a state transition
171    * from {@code A -> B} then {@code A.compareTo(B) < 0}. N.B. The converse is not true, i.e. if
172    * {@code A.compareTo(B) < 0} then there is <b>not</b> guaranteed to be a valid state transition
173    * {@code A -> B}.
174    *
175    * @since 9.0 (in 1.0 as {@code com.google.common.base.Service.State})
176    */
177   enum State {
178     /** A service in this state is inactive. It does minimal work and consumes minimal resources. */
179     NEW,
180 
181     /** A service in this state is transitioning to {@link #RUNNING}. */
182     STARTING,
183 
184     /** A service in this state is operational. */
185     RUNNING,
186 
187     /** A service in this state is transitioning to {@link #TERMINATED}. */
188     STOPPING,
189 
190     /**
191      * A service in this state has completed execution normally. It does minimal work and consumes
192      * minimal resources.
193      */
194     TERMINATED,
195 
196     /**
197      * A service in this state has encountered a problem and may not be operational. It cannot be
198      * started nor stopped.
199      */
200     FAILED,
201   }
202 
203   /**
204    * A listener for the various state changes that a {@link Service} goes through in its lifecycle.
205    *
206    * <p>All methods are no-ops by default, implementors should override the ones they care about.
207    *
208    * @author Luke Sandberg
209    * @since 15.0 (present as an interface in 13.0)
210    */
211   abstract class Listener {
212     /**
213      * Called when the service transitions from {@linkplain State#NEW NEW} to {@linkplain
214      * State#STARTING STARTING}. This occurs when {@link Service#startAsync} is called the first
215      * time.
216      */
starting()217     public void starting() {}
218 
219     /**
220      * Called when the service transitions from {@linkplain State#STARTING STARTING} to {@linkplain
221      * State#RUNNING RUNNING}. This occurs when a service has successfully started.
222      */
running()223     public void running() {}
224 
225     /**
226      * Called when the service transitions to the {@linkplain State#STOPPING STOPPING} state. The
227      * only valid values for {@code from} are {@linkplain State#STARTING STARTING} or {@linkplain
228      * State#RUNNING RUNNING}. This occurs when {@link Service#stopAsync} is called.
229      *
230      * @param from The previous state that is being transitioned from.
231      */
stopping(State from)232     public void stopping(State from) {}
233 
234     /**
235      * Called when the service transitions to the {@linkplain State#TERMINATED TERMINATED} state.
236      * The {@linkplain State#TERMINATED TERMINATED} state is a terminal state in the transition
237      * diagram. Therefore, if this method is called, no other methods will be called on the {@link
238      * Listener}.
239      *
240      * @param from The previous state that is being transitioned from. Failure can occur in any
241      *     state with the exception of {@linkplain State#FAILED FAILED} and {@linkplain
242      *     State#TERMINATED TERMINATED}.
243      */
terminated(State from)244     public void terminated(State from) {}
245 
246     /**
247      * Called when the service transitions to the {@linkplain State#FAILED FAILED} state. The
248      * {@linkplain State#FAILED FAILED} state is a terminal state in the transition diagram.
249      * Therefore, if this method is called, no other methods will be called on the {@link Listener}.
250      *
251      * @param from The previous state that is being transitioned from. Failure can occur in any
252      *     state with the exception of {@linkplain State#NEW NEW} or {@linkplain State#TERMINATED
253      *     TERMINATED}.
254      * @param failure The exception that caused the failure.
255      */
failed(State from, Throwable failure)256     public void failed(State from, Throwable failure) {}
257   }
258 }
259