Package org.jbpm.job.executor

Source Code of org.jbpm.job.executor.JobExecutorThread

package org.jbpm.job.executor;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.db.JobSession;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.job.Job;
import org.jbpm.persistence.JbpmPersistenceException;
import org.jbpm.persistence.db.DbPersistenceService;
import org.jbpm.persistence.db.StaleObjectLogConfigurer;

public class JobExecutorThread extends Thread {

  final JobExecutor jobExecutor;
  final JbpmConfiguration jbpmConfiguration;
  final int idleInterval;
  final int maxIdleInterval;
  final long maxLockTime;

  int currentIdleInterval;
  volatile boolean isActive = true;

  public JobExecutorThread(String name, JobExecutor jobExecutor) {
    super(name);
    this.jobExecutor = jobExecutor;
    this.jbpmConfiguration = jobExecutor.getJbpmConfiguration();
    this.idleInterval = jobExecutor.getIdleInterval();
    this.maxIdleInterval = jobExecutor.getMaxIdleInterval();
    this.maxLockTime = jobExecutor.getMaxLockTime();
  }

  /** @deprecated As of jBPM 3.2.6, replaced by {@link #JobExecutorThread(String, JobExecutor)} */
  @Deprecated
  public JobExecutorThread(String name, JobExecutor jobExecutor,
      JbpmConfiguration jbpmConfiguration, int idleInterval, int maxIdleInterval, long maxLockTime,
      int maxHistory) {
    super(name);
    this.jobExecutor = jobExecutor;
    this.jbpmConfiguration = jbpmConfiguration;
    this.idleInterval = idleInterval;
    this.maxIdleInterval = maxIdleInterval;
    this.maxLockTime = maxLockTime;
  }

  public void run() {
    currentIdleInterval = idleInterval;
    while (isActive) {
      try {
        Collection<Job> acquiredJobs = acquireJobs();

        if (!acquiredJobs.isEmpty()) {
          for (Job job : acquiredJobs) {
            executeJob(job);
            if (!isActive) break;
          }
        }
        else if (isActive) {
          long waitPeriod = getWaitPeriod();
          if (waitPeriod > 0) {
            synchronized (jobExecutor) {
              jobExecutor.wait(waitPeriod);
            }
          }
        }

        // no exception, resetting the currentIdleInterval
        currentIdleInterval = idleInterval;
      }
      catch (InterruptedException e) {
        log.info((isActive ? "active" : "inactive")
            + " job executor thread '"
            + getName()
            + "' got interrupted");
      }
      catch (Exception e) {
        log.error("exception in job executor thread. waiting "
            + currentIdleInterval
            + " milliseconds", e);
        try {
          synchronized (jobExecutor) {
            jobExecutor.wait(currentIdleInterval);
          }
        }
        catch (InterruptedException e2) {
          log.debug("delay after exception got interrupted", e2);
        }
        // after an exception, the current idle interval is doubled to prevent
        // continuous exception generation when e.g. the db is unreachable
        currentIdleInterval *= 2;
        if (currentIdleInterval > maxIdleInterval || currentIdleInterval < 0) {
          currentIdleInterval = maxIdleInterval;
        }
      }
    }
    log.info(getName() + " leaves cyberspace");
  }

  protected Collection<Job> acquireJobs() {
    Collection<Job> acquiredJobs = Collections.emptyList();
    synchronized (jobExecutor) {
      JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
      try {
        log.debug("querying for acquirable job...");
        String lockOwner = getName();
        JobSession jobSession = jbpmContext.getJobSession();
        Job job = jobSession.getFirstAcquirableJob(lockOwner);

        if (job != null) {
          if (job.isExclusive()) {
            ProcessInstance processInstance = job.getProcessInstance();
            log.debug("loaded exclusive " + job + ", finding exclusive jobs for " + processInstance);
            acquiredJobs = jobSession.findExclusiveJobs(lockOwner, processInstance);
            log.debug("trying to obtain locks on " + acquiredJobs + " for " + processInstance);
          }
          else {
            acquiredJobs = Collections.singletonList(job);
            log.debug("trying to obtain lock on " + job);
          }

          Date lockTime = new Date();
          for (Job acquiredJob : acquiredJobs) {
            acquiredJob.setLockOwner(lockOwner);
            acquiredJob.setLockTime(lockTime);
          }
        }
        else {
          log.debug("no acquirable jobs");
        }
      }
      finally {
        try {
          jbpmContext.close();
          log.debug("obtained lock on jobs: " + acquiredJobs);
        }
        catch (JbpmPersistenceException e) {
          // if this is a stale state exception, keep it quiet
          if (DbPersistenceService.isStaleStateException(e)) {
            log.debug("optimistic locking failed, could not acquire jobs " + acquiredJobs);
            StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
                "optimistic locking failed, could not acquire jobs " + acquiredJobs, e);
            acquiredJobs = Collections.emptyList();
          }
          else {
            throw e;
          }
        }
      }
    }
    return acquiredJobs;
  }

  protected void executeJob(Job job) {
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {
      JobSession jobSession = jbpmContext.getJobSession();
      job = jobSession.loadJob(job.getId());

      log.debug("executing " + job);
      try {
        if (job.execute(jbpmContext)) {
          jobSession.deleteJob(job);
        }
      }
      catch (Exception e) {
        log.debug("exception while executing " + job, e);
        if (!DbPersistenceService.isPersistenceException(e)) {
          StringWriter memoryWriter = new StringWriter();
          e.printStackTrace(new PrintWriter(memoryWriter));
          job.setException(memoryWriter.toString());
          job.setRetries(job.getRetries() - 1);
        }
        else {
          // allowing a transaction to proceed after a persistence exception is unsafe
          jbpmContext.setRollbackOnly();
        }
      }

      // if this job is locked too long
      long totalLockTimeInMillis = System.currentTimeMillis() - job.getLockTime().getTime();
      if (totalLockTimeInMillis > maxLockTime) {
        jbpmContext.setRollbackOnly();
      }
    }
    finally {
      try {
        jbpmContext.close();
      }
      catch (JbpmPersistenceException e) {
        // if this is a stale state exception, keep it quiet
        if (DbPersistenceService.isStaleStateException(e)) {
          log.debug("optimistic locking failed, could not complete job " + job);
          StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
              "optimistic locking failed, could not complete job " + job, e);
        }
        else {
          throw e;
        }
      }
    }
  }

  protected Date getNextDueDate() {
    Date nextDueDate = null;
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {
      JobSession jobSession = jbpmContext.getJobSession();
      Collection<Long> jobIdsToIgnore = jobExecutor.getMonitoredJobIds();
      Job job = jobSession.getFirstDueJob(getName(), jobIdsToIgnore);
      if (job != null) {
        nextDueDate = job.getDueDate();
        jobExecutor.addMonitoredJobId(getName(), job.getId());
      }
    }
    finally {
      try {
        jbpmContext.close();
      }
      catch (JbpmPersistenceException e) {
        // if this is a stale state exception, keep it quiet
        if (DbPersistenceService.isStaleStateException(e)) {
          log.debug("optimistic locking failed, could not return next due date: " + nextDueDate);
          StaleObjectLogConfigurer.getStaleObjectExceptionsLog().error(
              "optimistic locking failed, could not return next due date: " + nextDueDate, e);
          nextDueDate = null;
        }
        else {
          throw e;
        }
      }
    }
    return nextDueDate;
  }

  protected long getWaitPeriod() {
    long interval = currentIdleInterval;
    Date nextDueDate = getNextDueDate();
    if (nextDueDate != null) {
      long currentTime = System.currentTimeMillis();
      long nextDueTime = nextDueDate.getTime();
      if (nextDueTime < currentTime + currentIdleInterval) {
        interval = nextDueTime - currentTime;
      }
    }
    if (interval < 0) {
      interval = 0;
    }
    return interval;
  }

  /**
   * @deprecated As of jBPM 3.2.3, replaced by {@link #deactivate()}
   */
  public void setActive(boolean isActive) {
    if (isActive == false) deactivate();
  }

  /**
   * Indicates that this thread should stop running. Execution will cease shortly afterwards.
   */
  public void deactivate() {
    if (isActive) {
      isActive = false;
      interrupt();
    }
  }

  private static Log log = LogFactory.getLog(JobExecutorThread.class);
}
TOP

Related Classes of org.jbpm.job.executor.JobExecutorThread

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.