001/*
002 * (C) Copyright 2012-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Florent Guillaume
016 */
017package org.nuxeo.ecm.core.work.api;
018
019import java.util.List;
020import java.util.concurrent.TimeUnit;
021
022import org.nuxeo.ecm.core.work.api.Work.State;
023
024/**
025 * A {@link WorkManager} executes {@link Work} instances asynchronously.
026 * <p>
027 * A {@link Work} can be scheduled by calling {@link #schedule}.
028 * <p>
029 * Work is executed in a thread pool and a work queue that depends on the work's category.
030 *
031 * @since 5.6
032 */
033public interface WorkManager {
034
035    /**
036     * The scheduling policy to use when adding a work instance using {@link #schedule(Work, Scheduling)}.
037     */
038    enum Scheduling {
039        /**
040         * Always schedule the work.
041         */
042        ENQUEUE,
043        /**
044         * Any other scheduled work equals to this one is removed from scheduling and canceled first, before this work
045         * is scheduled.
046         */
047        CANCEL_SCHEDULED,
048        /**
049         * If there is a scheduled work equals to this one, then don't schedule the work.
050         */
051        IF_NOT_SCHEDULED(State.SCHEDULED),
052        /**
053         * If there is a running work equals to this one, then don't schedule the work.
054         *
055         * @deprecated unused
056         */
057        @Deprecated
058        IF_NOT_RUNNING(State.RUNNING),
059        /**
060         * If there is a running or scheduled work equals to this one, then don't schedule the work.
061         */
062        IF_NOT_RUNNING_OR_SCHEDULED;
063
064        public final State state;
065
066        private Scheduling() {
067            state = null;
068        }
069
070        private Scheduling(State state) {
071            this.state = state;
072        }
073    }
074
075    /**
076     * Lists the ids of the existing work queues.
077     *
078     * @return the list of queue ids
079     */
080    List<String> getWorkQueueIds();
081
082    /**
083     * Gets the queue id used for a given work category.
084     *
085     * @param category the category
086     * @return the queue id
087     */
088    String getCategoryQueueId(String category);
089
090    /**
091     * Gets the work queue descriptor for a given queue id.
092     *
093     * @param queueId the queue id
094     * @return the work queue descriptor, or {@code null}
095     */
096    WorkQueueDescriptor getWorkQueueDescriptor(String queueId);
097
098    /**
099     * Starts up this {@link WorkManager} and attempts to resume work previously suspended and saved at
100     * {@link #shutdown} time.
101     */
102    void init();
103
104    /**
105     * Shuts down a work queue and attempts to suspend and save the running and scheduled work instances.
106     *
107     * @param queueId the queue id
108     * @param timeout the time to wait
109     * @param unit the timeout unit
110     * @return {@code true} if shutdown is done, {@code false} if there are still some threads executing after the
111     *         timeout
112     */
113    boolean shutdownQueue(String queueId, long timeout, TimeUnit unit) throws InterruptedException;
114
115    /**
116     * Shuts down this {@link WorkManager} and attempts to suspend and save the running and scheduled work instances.
117     *
118     * @param timeout the time to wait
119     * @param unit the timeout unit
120     * @return {@code true} if shutdown is done, {@code false} if there are still some threads executing after the
121     *         timeout
122     */
123    boolean shutdown(long timeout, TimeUnit unit) throws InterruptedException;
124
125    /**
126     * Schedules work for execution at a later time.
127     * <p>
128     * This method is identical to {@link #schedule(Work, boolean)} with {@code afterCommit = false}.
129     *
130     * @param work the work to execute
131     */
132    void schedule(Work work);
133
134    /**
135     * Schedules work for execution at a later time, after the current transaction (if any) has committed.
136     *
137     * @param work the work to execute
138     * @param afterCommit if {@code true} and the work is scheduled, it will only be run after the current transaction
139     *            (if any) has committed
140     */
141    void schedule(Work work, boolean afterCommit);
142
143    /**
144     * Schedules work for execution at a later time, with a specific {@linkplain Scheduling scheduling} policy.
145     * <p>
146     * This method is identical to {@link #schedule(Work, Scheduling, boolean)} with {@code afterCommit = false}.
147     *
148     * @param work the work to execute
149     * @param scheduling the scheduling policy
150     * @see #schedule(Work)
151     */
152    void schedule(Work work, Scheduling scheduling);
153
154    /**
155     * Schedules work for execution at a later time, with a specific {@linkplain Scheduling scheduling} policy.
156     *
157     * @param work the work to execute
158     * @param scheduling the scheduling policy
159     * @param afterCommit if {@code true} and the work is scheduled, it will only be run after the current transaction
160     *            (if any) has committed
161     * @see #schedule(Work)
162     */
163    void schedule(Work work, Scheduling scheduling, boolean afterCommit);
164
165    /**
166     * Finds a work instance.
167     *
168     * @param work the work to find
169     * @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
170     *            RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for non-completed
171     * @param useEquals ignored, always uses work id equality
172     * @param pos ignored, pass null
173     * @return the found work instance, or {@code null} if not found
174     * @deprecated since 5.8, use {@link #getWorkState} instead
175     */
176    @Deprecated
177    Work find(Work work, State state, boolean useEquals, int[] pos);
178
179    /**
180     * Finds a work instance.
181     *
182     * @param workId the id of the work to find
183     * @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
184     *            RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for non-completed
185     * @return the found work instance, or {@code null} if not found
186     * @since 7.3
187     */
188    Work find(String workId, State state);
189
190    /**
191     * Finds a work result.
192     *
193     * @param workId the id of the work to find the result
194     * @return the found work result, or {@code null} if there is no result or if work is not {@link State#COMPLETED
195     *         COMPLETED}
196     * @since 7.4
197     */
198    String findResult(String workId);
199
200    /**
201     * Gets the state in which a work instance is.
202     * <p>
203     * This can be {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING RUNNING}, {@link State#COMPLETED COMPLETED},
204     * {@link State#CANCELED} or {@link State#FAILED}.
205     *
206     * @param workId the id of the work to find
207     * @return the work state, or {@code null} if not found
208     * @since 5.8
209     */
210    State getWorkState(String workId);
211
212    /**
213     * Lists the work instances in a given queue in a defined state.
214     *
215     * @param queueId the queue id
216     * @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
217     *            RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for non-completed
218     * @return the list of work instances in the given state
219     */
220    List<Work> listWork(String queueId, State state);
221
222    /**
223     * Lists the work ids in a given queue in a defined state.
224     *
225     * @param queueId the queue id
226     * @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
227     *            RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for non-completed
228     * @return the list of work ids in the given state
229     * @since 5.8
230     */
231    List<String> listWorkIds(String queueId, State state);
232
233    /**
234     * Gets the number of work instances in a given queue in a defined state.
235     * <p>
236     *
237     * @param queueId the queue id
238     * @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
239     *            RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for non-completed (
240     *            {@link State#SCHEDULED SCHEDULED} or {@link State#RUNNING RUNNING})
241     * @return the number of work instances in the given state
242     * @since 5.8
243     */
244    int getQueueSize(String queueId, State state);
245
246    /**
247     * Gets the size of the non-completed work (scheduled + running) for a give queue.
248     *
249     * @param queueId the queue id
250     * @return the number of non-completed work instances
251     * @deprecated since 5.8, use {@link #getQueueSize} with {@code null} state instead
252     */
253    @Deprecated
254    int getNonCompletedWorkSize(String queueId);
255
256    /**
257     * Waits for completion of work in a given queue.
258     *
259     * @param queueId the queue id
260     * @param timeout the time to wait
261     * @param unit the timeout unit
262     * @return {@code true} if all work completed in the queue, or {@code false} if there is still some non-completed
263     *         work after the timeout
264     */
265    boolean awaitCompletion(String queueId, long timeout, TimeUnit unit) throws InterruptedException;
266
267    /**
268     * Waits for completion of all work.
269     *
270     * @param timeout the time to wait
271     * @param unit the timeout unit
272     * @return {@code true} if all work completed, or {@code false} if there is still some non-completed work after the
273     *         timeout
274     */
275    boolean awaitCompletion(long timeout, TimeUnit unit) throws InterruptedException;
276
277    /**
278     * Clears the list of completed work instances for a given queue.
279     *
280     * @param queueId the queue id
281     */
282    void clearCompletedWork(String queueId);
283
284    /**
285     * Clears the list of completed work instances older than the given time.
286     *
287     * @param completionTime the completion time (milliseconds since epoch) before which completed work instances are
288     *            cleared, or {@code 0} for all
289     */
290    void clearCompletedWork(long completionTime);
291
292    /**
293     * Clears the list of completed work instances older than what's configured for each queue.
294     */
295    void cleanup();
296
297    /**
298     * @return {@code true} if active
299     * @see org.nuxeo.runtime.model.DefaultComponent#applicationStarted(org.nuxeo.runtime.model.ComponentContext)
300     * @see #init()
301     * @see #shutdown(long, TimeUnit)
302     * @since 6.0
303     */
304    boolean isStarted();
305
306}