Package org.activiti.async.executor.hazelcast

Source Code of org.activiti.async.executor.hazelcast.HazelCastDistributedQueueBasedAsyncExecutor

package org.activiti.async.executor.hazelcast;

import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.activiti.engine.impl.asyncexecutor.AsyncExecutor;
import org.activiti.engine.impl.asyncexecutor.ExecuteAsyncRunnable;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.impl.persistence.entity.JobEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.HazelcastInstanceNotActiveException;
import com.hazelcast.core.IQueue;
import com.hazelcast.monitor.LocalQueueStats;

/**
* Implementation of the Activiti {@link AsyncExecutor} using a distributed queue where the jobs
* to be executed are put on. One of the distributed nodes will take the job off the queue,
* and hand it off the local thread pool.
*
* Needs a config file (hazelcast.xml on the classpath) that defines a queue with the name 'activiti':
*
* for example:
*
* <hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.3.xsd"
           xmlns="http://www.hazelcast.com/schema/config"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <group>
       ...
    </group>
   
    <network>
       ...
    </network>
   
   
     <queue name="activiti">
        <!--
            Maximum size of the queue. When a JVM's local queue size reaches the maximum,
            all put/offer operations will get blocked until the queue size
            of the JVM goes down below the maximum.
            Any integer between 0 and Integer.MAX_VALUE. 0 means
            Integer.MAX_VALUE. Default is 0.
        -->
        <max-size>1024</max-size>
        <!--
            Number of backups. If 1 is set as the backup-count for example,
            then all entries of the map will be copied to another JVM for
            fail-safety. 0 means no backup.
        -->
        <backup-count>0</backup-count>

        <!--
            Number of async backups. 0 means no backup.
        -->
        <async-backup-count>0</async-backup-count>

        <empty-queue-ttl>-1</empty-queue-ttl>
    </queue>


</hazelcast>
*
* @author Joram Barrez
*/
public class HazelCastDistributedQueueBasedAsyncExecutor implements AsyncExecutor {
 
  private static final Logger logger = LoggerFactory.getLogger(HazelCastDistributedQueueBasedAsyncExecutor.class);
 
  private static final String QUEUE_NAME = "activiti";
 
  // Injecteable
  protected boolean isAutoActivate;
  protected CommandExecutor commandExecutor;
  protected int maxTimerJobsPerAcquisition = 1;
  protected int maxAsyncJobsDuePerAcquisition = 1;
  protected int defaultTimerJobAcquireWaitTimeInMillis = 10 * 1000;
  protected int defaultAsyncJobAcquireWaitTimeInMillis = 10 * 1000;
   
  protected String lockOwner = UUID.randomUUID().toString();
  protected int timerLockTimeInMillis = 5 * 60 * 1000;
  protected int asyncJobLockTimeInMillis = 5 * 60 * 1000;
 
   /** 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 time (in milliseconds) a thread used for job execution must be kept alive before it is
   * destroyed. Default setting is 0. Having a non-default setting of 0 takes resources,
   * but in the case of many job executions it avoids creating new threads all the time.
   */
  protected long keepAliveTime = 60000L;

  /** The size of the queue on which jobs to be executed are placed */
  protected int queueSize = 100;
 
  /** The time (in seconds) that is waited to gracefully shut down the threadpool used for job execution */
  protected long secondsToWaitOnShutdown = 60L;
 
  // Runtime
  protected boolean isActive;
  protected HazelcastInstance hazelcastInstance;
  protected IQueue<JobEntity> jobQueue;
 
  protected Thread jobQueueListenerThread;
  protected BlockingQueue<Runnable> threadPoolQueue;
  protected ExecutorService executorService;
 
  @Override
  public void start() {
    if (isActive) {
      return;
    }

    logger.info("Starting up the Hazelcast async job executor [{}].", getClass().getName());

    hazelcastInstance = Hazelcast.newHazelcastInstance();
    jobQueue = hazelcastInstance.getQueue(QUEUE_NAME);

    threadPoolQueue = new ArrayBlockingQueue<Runnable>(queueSize);
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, threadPoolQueue);
    threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    executorService = threadPoolExecutor;
   
    isActive = true;
    initJobQueueListener();
  }
 
  protected void initJobQueueListener() {
    jobQueueListenerThread = new Thread(new Runnable() {
     
      public void run() {
        while (isActive) {
          JobEntity job = null;
          try {
            job = jobQueue.take(); // Blocking
          } catch (InterruptedException e1) {
            // Do nothing, this can happen when shutting down
          }
         
          if (job != null) {
            executorService.execute(new ExecuteAsyncRunnable(job, commandExecutor));
          }
        }
      }
     
    });
    jobQueueListenerThread.start();
  }

  @Override
  public void shutdown() {
   
    // Shut down local execution service
    try {
      executorService.shutdown();
      executorService.awaitTermination(secondsToWaitOnShutdown, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      logger.warn("Exception while waiting for executor service shutdown", e);
    }
   
    // Shut down listener thread
    isActive = false;
   
    LocalQueueStats localQueueStats = jobQueue.getLocalQueueStats();
    logger.info("This async job executor has processed " + localQueueStats.getPollOperationCount());

    // Shut down hazelcast
    try {
      hazelcastInstance.shutdown();
    } catch (HazelcastInstanceNotActiveException e) {
      // Nothing to do
    }
  }
 
  @Override
  public void executeAsyncJob(JobEntity job) {
    try {
      jobQueue.put(job);
    } catch (InterruptedException e) {
      // Nothing to do about it, can happen at shutdown for example
    }
  }
 
  @Override
  public boolean isActive() {
    return isActive;
  }
 
  @Override
  public CommandExecutor getCommandExecutor() {
    return commandExecutor;
  }


  @Override
  public void setCommandExecutor(CommandExecutor commandExecutor) {
    this.commandExecutor = commandExecutor;
  }

  @Override
  public boolean isAutoActivate() {
    return isAutoActivate;
  }

  @Override
  public void setAutoActivate(boolean isAutoActivate) {
    this.isAutoActivate = isAutoActivate;
  }

  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 getKeepAliveTime() {
    return keepAliveTime;
  }

  public void setKeepAliveTime(long keepAliveTime) {
    this.keepAliveTime = keepAliveTime;
  }

  public int getQueueSize() {
    return queueSize;
  }

  public void setQueueSize(int queueSize) {
    this.queueSize = queueSize;
  }

  public long getSecondsToWaitOnShutdown() {
    return secondsToWaitOnShutdown;
  }

  public void setSecondsToWaitOnShutdown(long secondsToWaitOnShutdown) {
    this.secondsToWaitOnShutdown = secondsToWaitOnShutdown;
  }

  public void setActive(boolean isActive) {
    this.isActive = isActive;
  }
 

  public String getLockOwner() {
    return lockOwner;
  }

  public void setLockOwner(String lockOwner) {
    this.lockOwner = lockOwner;
  }

  public int getTimerLockTimeInMillis() {
    return timerLockTimeInMillis;
  }

  public void setTimerLockTimeInMillis(int timerLockTimeInMillis) {
    this.timerLockTimeInMillis = timerLockTimeInMillis;
  }

  public int getAsyncJobLockTimeInMillis() {
    return asyncJobLockTimeInMillis;
  }

  public void setAsyncJobLockTimeInMillis(int asyncJobLockTimeInMillis) {
    this.asyncJobLockTimeInMillis = asyncJobLockTimeInMillis;
  }

  public int getMaxTimerJobsPerAcquisition() {
    return maxTimerJobsPerAcquisition;
  }

  public void setMaxTimerJobsPerAcquisition(int maxTimerJobsPerAcquisition) {
    this.maxTimerJobsPerAcquisition = maxTimerJobsPerAcquisition;
  }

  public int getMaxAsyncJobsDuePerAcquisition() {
    return maxAsyncJobsDuePerAcquisition;
  }

  public void setMaxAsyncJobsDuePerAcquisition(int maxAsyncJobsDuePerAcquisition) {
    this.maxAsyncJobsDuePerAcquisition = maxAsyncJobsDuePerAcquisition;
  }

  public int getDefaultTimerJobAcquireWaitTimeInMillis() {
    return defaultTimerJobAcquireWaitTimeInMillis;
  }

  public void setDefaultTimerJobAcquireWaitTimeInMillis(
      int defaultTimerJobAcquireWaitTimeInMillis) {
    this.defaultTimerJobAcquireWaitTimeInMillis = defaultTimerJobAcquireWaitTimeInMillis;
  }

  public int getDefaultAsyncJobAcquireWaitTimeInMillis() {
    return defaultAsyncJobAcquireWaitTimeInMillis;
  }

  public void setDefaultAsyncJobAcquireWaitTimeInMillis(
      int defaultAsyncJobAcquireWaitTimeInMillis) {
    this.defaultAsyncJobAcquireWaitTimeInMillis = defaultAsyncJobAcquireWaitTimeInMillis;
  }
 
}
TOP

Related Classes of org.activiti.async.executor.hazelcast.HazelCastDistributedQueueBasedAsyncExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.