All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.activiti.engine.impl.jobexecutor.SimulationAcquireJobsRunnable Maven / Gradle / Ivy

The newest version!
/* 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.jobexecutor;

import java.util.Date;
import java.util.List;

import org.activiti.crystalball.simulator.SimulationEvent;
import org.activiti.crystalball.simulator.SimulationRunContext;
import org.activiti.engine.ActivitiOptimisticLockingException;
import org.activiti.engine.impl.Page;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.impl.persistence.entity.TimerEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * "thread" has to be driven by simulation time.
 * In fact new thread is not started. Simulation is driven by simulation time. 
 * In case of thread for acquiring jobs, synchronization will be over complicated.
 *
 * @author martin.grofcik
 */
public class SimulationAcquireJobsRunnable extends AcquireJobsRunnableImpl {
	
	private static Logger log = LoggerFactory.getLogger(SimulationAcquireJobsRunnable.class.getName());

	public SimulationAcquireJobsRunnable(JobExecutor jobExecutor) {
	    super(jobExecutor);
	}
	
	  public synchronized void run() {
//		    if (log.isLoggable(Level.INFO)) {
//		      log.info(jobExecutor.getName() + " starting to acquire jobs");
//		    }

		    final CommandExecutor commandExecutor = jobExecutor.getCommandExecutor();

		    // while is not needed - repetition is done by event scheduling 
//		    while (!isInterrupted) {
              isWaiting.set(false);
		      int maxJobsPerAcquisition = jobExecutor.getMaxJobsPerAcquisition();

		      try {
		        AcquiredJobs acquiredJobs = commandExecutor.execute(jobExecutor.getAcquireJobsCmd());

		        for (List jobIds : acquiredJobs.getJobIdBatches()) {
		          jobExecutor.executeJobs(jobIds);
		        }

		        // if all jobs were executed
		        millisToWait = jobExecutor.getWaitTimeInMillis();
		        int jobsAcquired = acquiredJobs.getJobIdBatches().size();
		        if (jobsAcquired < maxJobsPerAcquisition) {
		          
		          isJobAdded = false;
		          
		          // check if the next timer should fire before the normal sleep time is over
		          Date duedate = new Date(SimulationRunContext.getClock().getCurrentTime().getTime() + millisToWait);
		          List nextTimers = commandExecutor.execute(new GetUnlockedTimersByDuedateCmd(duedate, new Page(0, 1)));
		          
		          if (!nextTimers.isEmpty()) {
		          long millisTillNextTimer = nextTimers.get(0).getDuedate().getTime() - SimulationRunContext.getClock().getCurrentTime().getTime();
		            if (millisTillNextTimer < millisToWait && millisTillNextTimer != 0) {
		              millisToWait = millisTillNextTimer;
		            }
		          }
		          
		        } else {
		          millisToWait = 0;
		        }

		      } catch (ActivitiOptimisticLockingException optimisticLockingException) { 
		        // See https://activiti.atlassian.net/browse/ACT-1390
		        log.trace("Optimistic locking exception during job acquisition. If you have multiple job executors running against the same database, " +
		          		"this exception means that this thread tried to acquire a job, which already was acquired by another job executor acquisition thread." +
		          		"This is expected behavior in a clustered environment. " +
		          		"You can ignore this message if you indeed have multiple job executor acquisition threads running against the same database. " +
		          		"Exception message: " + optimisticLockingException.getMessage());
		        
		      } catch (Exception e) {
		        log.error("exception during job acquisition: " + e.getMessage(), e);          
		        millisToWait = jobExecutor.getWaitTimeInMillis();
		      }

		      if ((millisToWait > 0) && (!isJobAdded)) {
		        try {
		          log.trace("job acquisition thread sleeping for " + millisToWait + " millis");
		          synchronized (MONITOR) {
		            if(!isInterrupted) {
		              isWaiting.set(true);

                  SimulationEvent event = new SimulationEvent.Builder(SimulationEvent.TYPE_ACQUIRE_JOB_NOTIFICATION_EVENT).
                    simulationTime(SimulationRunContext.getClock().getCurrentTime().getTime() + millisToWait).
                    property(this).
                    build();
                  SimulationRunContext.getEventCalendar().addEvent(event);
		              // do not need to wait. - event scheduling is enough
		              //MONITOR.wait(millisToWait);
		            }
		          } 
		          		          
		          log.trace("job acquisition thread woke up");
		        } finally {
//		          isWaiting.set(false);
		        }
		      } else {
		    	  // schedule run now
            SimulationEvent event = new SimulationEvent.Builder(SimulationEvent.TYPE_ACQUIRE_JOB_NOTIFICATION_EVENT).
              simulationTime(SimulationRunContext.getClock().getCurrentTime().getTime()).
              property(this).
              build();
            SimulationRunContext.getEventCalendar().addEvent(event);
		      }
//		    }
		    
//		    if (log.isLoggable(Level.INFO)) {
//		      log.info(jobExecutor.getName() + " stopped job acquisition");
//		    }
	  }
	  
	  public void stop() {
	    synchronized (MONITOR) {
	      isInterrupted = true; 
//	      if(isWaiting.compareAndSet(true, false)) {
	    	  // Notify is not needed - event is enough
//	    	  SimulationContext.getEventCalendar().addEvent( new SimulationEvent(
//            		  ClockUtil.getCurrentTime().getTime(),  
//            		  SimulationEvent.TYPE_ACQUIRE_JOB_NOTIFICATION_EVENT, 
//            		  this) );
              //MONITOR.notifyAll();
//	        }
	      }
	  }

	  public void jobWasAdded() {    
		    isJobAdded = true;
		    if(isWaiting.compareAndSet(true, false)) { 
		      // ensures we only notify once
		      // I am OK with the race condition      
		      synchronized (MONITOR) {
//		        MONITOR.notifyAll();
		    	//Notify is not needed - event is enough
            SimulationEvent event = new SimulationEvent.Builder(SimulationEvent.TYPE_ACQUIRE_JOB_NOTIFICATION_EVENT).
              simulationTime(SimulationRunContext.getClock().getCurrentTime().getTime()).
              property(this).
              build();
            SimulationRunContext.getEventCalendar().addEvent(event);
		      }
		    }    
		  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy