/* 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.
*/
package org.activiti.engine.impl.asyncexecutor;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.JobEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Joram Barrez
* @author Tijs Rademakers
*/
public class DefaultAsyncJobExecutor extends AbstractAsyncJobExecutor {
private static Logger log = LoggerFactory.getLogger(DefaultAsyncJobExecutor.class);
/** The minimal number of threads that are kept alive in the threadpool for job execution */
protected int corePoolSize = 2;
/** The maximum number of threads that are kept alive in the threadpool for job execution */
protected int maxPoolSize = 10;
/** The size of the queue on which jobs to be executed are placed */
protected int queueSize = 100;
/** The queue used for job execution work */
protected BlockingQueue<Runnable> threadPoolQueue;
/** The executor service used for job execution */
protected ExecutorService executorService;
/** The time (in seconds) that is waited to gracefully shut down the threadpool used for job execution */
protected long secondsToWaitOnShutdown = 60L;
protected boolean executeAsyncJob(Runnable runnable) {
try {
executorService.execute(runnable);
return true;
} catch (RejectedExecutionException e) {
// When a RejectedExecutionException is caught, this means that the queue for holding the jobs
// that are to be executed is full and can't store more.
// Return false so the job can be unlocked and (if wanted) the acquiring can be throttled.
return false;
}
}
protected Runnable createRunnableForJob(final JobEntity job) {
return executeAsyncRunnableFactory.createExecuteAsyncRunnable(job, commandExecutor);
}
protected void unlockJob(final JobEntity job, CommandContext commandContext) {
commandContext.getJobEntityManager().unacquireJob(job.getId());
}
protected void startExecutingAsyncJobs() {
if (threadPoolQueue==null) {
log.info("Creating thread pool queue of size {}", queueSize);
threadPoolQueue = new ArrayBlockingQueue<Runnable>(queueSize);
}
if (executorService==null) {
log.info("Creating executor service with corePoolSize {}, maxPoolSize {} and keepAliveTime {}",
corePoolSize, maxPoolSize, keepAliveTime);
executorService = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, threadPoolQueue);
}
startJobAcquisitionThread();
}
protected void stopExecutingAsyncJobs() {
stopJobAcquisitionThread();
// Ask the thread pool to finish and exit
executorService.shutdown();
// Waits for 1 minute to finish all currently executing jobs
try {
if(!executorService.awaitTermination(secondsToWaitOnShutdown, TimeUnit.SECONDS)) {
log.warn("Timeout during shutdown of async job executor. "
+ "The current running jobs could not end within "
+ secondsToWaitOnShutdown + " seconds after shutdown operation.");
}
} catch (InterruptedException e) {
log.warn("Interrupted while shutting down the async job executor. ", e);
}
executorService = null;
}
public int getQueueSize() {
return queueSize;
}
public void setQueueSize(int queueSize) {
this.queueSize = queueSize;
}
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public long getSecondsToWaitOnShutdown() {
return secondsToWaitOnShutdown;
}
public void setSecondsToWaitOnShutdown(long secondsToWaitOnShutdown) {
this.secondsToWaitOnShutdown = secondsToWaitOnShutdown;
}
public BlockingQueue<Runnable> getThreadPoolQueue() {
return threadPoolQueue;
}
public void setThreadPoolQueue(BlockingQueue<Runnable> threadPoolQueue) {
this.threadPoolQueue = threadPoolQueue;
}
public ExecutorService getExecutorService() {
return executorService;
}
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
}