/*
* (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.core.work;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.work.api.Work;
import org.nuxeo.ecm.core.work.api.Work.State;
import org.nuxeo.ecm.core.work.api.WorkManager;
import org.nuxeo.ecm.core.work.api.WorkQueueDescriptor;
import org.nuxeo.ecm.core.work.api.WorkQueueMetrics;
/**
* Interface describing how the {@link WorkManager} implements queuing.
* <p>
* There are 4 structures maintained per-queue:
* <ul>
* <li>the work queue managed by the {@link ThreadPoolExecutor},</li>
* <li>the set of scheduled work, this enables to list a work as being scheduled while it has been removed from the
* queue by the {@link ThreadPoolExecutor} and not yet executed (not yet running).</li>
* <li>the set of running work,</li>
* <li>the set of completed work.</li>
*
* @since 5.8
*/
public interface WorkQueuing {
/**
* Starts up this {@link WorkQueuing} and attempts to resume work previously suspended and saved at shutdown time.
* @return
*/
NuxeoBlockingQueue init(WorkQueueDescriptor config);
/**
* Enable/disable this {@code queueId} processing
* @since 8.3
*/
void setActive(String queueId, boolean value);
/**
* Gets the blocking queue of work used by the {@link ThreadPoolExecutor}.
*
* @since 8.1
* @param queueId
* @return
*/
NuxeoBlockingQueue getQueue(String queueId);
/**
* Submit a work to the {@link ThreadPoolExecutor} and put it in the scheduled set.
*
* @param queueId the queue id
* @param work the work instance
* @since 8.1
*/
void workSchedule(String queueId, Work work);
/**
* Removes a work instance from scheduled set.
*
* @since 8.3
**/
void workCanceled(String queueId, Work work);
/**
* Put the work instance into the running set.
*
* @param queueId the queue id
* @param work the work instance
* @since 5.8
*/
void workRunning(String queueId, Work work);
/**
* Moves a work instance from the running set to the completed set.
*
* @param queueId the queue id
* @param work the work instance
* @since 5.8
*/
void workCompleted(String queueId, Work work);
/**
* Moves back a work instance from running set to the scheduled set.
*
* @since 8.3
**/
void workReschedule(String queueId, Work work);
/**
* Finds a work instance in the scheduled or running or completed sets.
*
* @param workId the id of the work to find
* @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
* RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for SCHEDULED or RUNNING
* @return the found work instance, or {@code null} if not found
*/
Work find(String workId, State state);
/**
* Finds a scheduled work instance and removes it from the scheduled queue.
*
* @param queueId the queue id
* @param workId the id of the work to find
* @since 5.8
*/
void removeScheduled(String queueId, String workId);
/**
* Checks if a work instance with the given id is in the given state.
*
* @param workId the work id
* @param state the state, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING RUNNING}, {@link State#COMPLETED
* COMPLETED}, or {@code null} for non-completed
* @return {@code true} if a work instance with the given id is in the given state
* @since 5.8
*/
boolean isWorkInState(String workId, State state);
/**
* Gets the state in which a work instance is.
* <p>
* This can be {@link State#SCHEDULED}, {@link State#RUNNING}, {@link State#COMPLETED}, {@link State#FAILED}, or
* {@link State#CANCELED}.
*
* @param workId the id of the work to find
* @return the work state, or {@code null} if not found
* @since 5.8
*/
State getWorkState(String workId);
/**
* Lists the work instances in a given queue in a defined state.
* <p>
* Note that an instance requested as RUNNING could be found SUSPENDING or SUSPENDED, and an instance requested as
* COMPLETED could be found FAILED.
*
* @param queueId the queue id
* @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
* RUNNING}, {@link State#COMPLETED COMPLETED}, or {@code null} for non-completed
* @return the list of work instances in the given state
*/
List<Work> listWork(String queueId, State state);
/**
* Lists the work ids in a given queue in a defined state.
*
* @param queueId the queue id
* @param state the state defining the state to look into, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING
* RUNNING}, or {@code null} for non-completed
* @return the list of work ids in the given state
*/
List<String> listWorkIds(String queueId, State state);
/**
* Gets the number of work instances in the given state in a given queue.
*
* @param queueId the queue id
* @param state the state, {@link State#SCHEDULED SCHEDULED}, {@link State#RUNNING RUNNING} or
* {@link State#COMPLETED COMPLETED}
* @return the number of scheduled work instances in the queue
* @since 5.8
*/
long count(String queueId, State state);
/**
* Returns current metrics of queue identified by the {@code queueId}
*
* @since 8.3
*/
WorkQueueMetrics metrics(String queueId);
/**
* Set the callback for debugging purpose
*
* @since 8.3
*/
void listen(Listener listener);
public interface Listener {
void queueActivated(WorkQueueMetrics metric);
void queueDeactivated(WorkQueueMetrics metric);
void queueChanged(Work work, WorkQueueMetrics metric);
static Listener lookupListener() {
final Log log = LogFactory.getLog(WorkQueuing.class);
if (log.isTraceEnabled()) {
class Tracing implements Listener {
private final Log log;
protected Tracing(Log log) {
this.log = log;
}
@Override
public void queueChanged(Work work, WorkQueueMetrics metrics) {
log.trace(String.format("%s -> changed on %s %s",
metrics,
work.getWorkInstanceState(),
work.getSchedulePath()));
}
@Override
public void queueActivated(WorkQueueMetrics metrics) {
log.trace(String.format("%s -> activated", metrics));
}
@Override
public void queueDeactivated(WorkQueueMetrics metrics) {
log.trace(String.format("%s -> deactivated", metrics));
}
}
return new Tracing(log);
} else {
class Null implements Listener {
@Override
public void queueActivated(WorkQueueMetrics metric) {
}
@Override
public void queueDeactivated(WorkQueueMetrics metric) {
}
@Override
public void queueChanged(Work work, WorkQueueMetrics metric) {
}
}
return new Null();
}
}
}
}