}
// Release the run barrier now so any concurrent HandleSlotFilled tasks
// will stop trying to release it.
runBarrier.setReleased();
UpdateSpec tempSpec = new UpdateSpec(rootJobKey);
tempSpec.getOrCreateTransaction("releaseRunBarrier").includeBarrier(runBarrier);
backEnd.save(tempSpec, jobRecord.getQueueSettings());
State jobState = jobRecord.getState();
switch (jobState) {
case WAITING_TO_RUN:
case RETRY:
// OK, proceed
break;
case WAITING_TO_FINALIZE:
logger.info("This job has already been run " + jobRecord);
return;
case STOPPED:
logger.info("This job has been stoped " + jobRecord);
return;
case CANCELED:
logger.info("This job has already been canceled " + jobRecord);
return;
case FINALIZED:
logger.info("This job has already been run " + jobRecord);
return;
}
// Deserialize the instance of Job and set some values on the instance
JobInstanceRecord record = jobRecord.getJobInstanceInflated();
if (null == record) {
throw new RuntimeException(
"Internal logic error:" + jobRecord + " does not have jobInstanceInflated.");
}
Job<?> job = record.getJobInstanceDeserialized();
UpdateSpec updateSpec = new UpdateSpec(rootJobKey);
setJobRecord(job, jobRecord);
String currentRunGUID = GUIDGenerator.nextGUID();
setCurrentRunGuid(job, currentRunGUID);
setUpdateSpec(job, updateSpec);
// Get the run() method we will invoke and its arguments
Object[] params = runBarrier.buildArgumentArray();
boolean callExceptionHandler = jobRecord.isCallExceptionHandler();
Method methodToExecute =
findJobMethodToInvoke(job.getClass(), callExceptionHandler, params);
if (callExceptionHandler && methodToExecute == null) {
// No matching exceptionHandler found. Propagate to the parent.
Throwable exceptionToHandle = (Throwable) params[0];
handleExceptionDuringRun(jobRecord, rootJobRecord, currentRunGUID, exceptionToHandle);
return;
}
if (logger.isLoggable(Level.FINEST)) {
StringBuilder builder = new StringBuilder(1024);
builder.append("Running " + jobRecord + " with params: ");
builder.append(StringUtils.toString(params));
logger.finest(builder.toString());
}
// Set the Job's start time and save the jobRecord now before we invoke
// run(). The start time will be displayed in the UI.
jobRecord.incrementAttemptNumber();
jobRecord.setStartTime(new Date());
tempSpec = new UpdateSpec(jobRecord.getRootJobKey());
tempSpec.getNonTransactionalGroup().includeJob(jobRecord);
if (!backEnd.saveWithJobStateCheck(
tempSpec, jobRecord.getQueueSettings(), jobKey, State.WAITING_TO_RUN, State.RETRY)) {
logger.info("Ignoring runJob request for job " + jobRecord + " which is not in a"
+ " WAITING_TO_RUN or a RETRY state");
return;
}
//TODO(user): Use the commented code to avoid resetting stack trace of rethrown exceptions
// List<Throwable> throwableParams = new ArrayList<Throwable>(params.length);
// for (Object param : params) {
// if (param instanceof Throwable) {
// throwableParams.add((Throwable) param);
// }
// }
// Invoke the run or handleException method. This has the side-effect of populating
// the UpdateSpec with any child job graph generated by the invoked method.
Value<?> returnValue = null;
Throwable caughtException = null;
try {
methodToExecute.setAccessible(true);
returnValue = (Value<?>) methodToExecute.invoke(job, params);
} catch (InvocationTargetException e) {
caughtException = e.getCause();
} catch (Throwable e) {
caughtException = e;
}
if (null != caughtException) {
//TODO(user): use the following condition to keep original exception trace
// if (!throwableParams.contains(caughtException)) {
// }
handleExceptionDuringRun(jobRecord, rootJobRecord, currentRunGUID, caughtException);
return;
}
// The run() method returned without error.
// We do all of the following in a transaction:
// (1) Check that the job is currently in the state WAITING_TO_RUN or RETRY
// (2) Change the state of the job to WAITING_TO_FINALIZE
// (3) Set the finalize slot to be the one generated by the run() method
// (4) Set the job's child graph GUID to be the currentRunGUID
// (5) Enqueue a FanoutTask that will fan-out to a set of
// HandleSlotFilledTasks for each of the slots that were immediately filled
// by the running of the job.
// See "http://goto/java-pipeline-model".
logger.finest("Job returned: " + returnValue);
registerSlotsWithBarrier(updateSpec, returnValue, rootJobKey, jobRecord.getKey(),
jobRecord.getQueueSettings(), currentRunGUID, finalizeBarrier);
jobRecord.setState(State.WAITING_TO_FINALIZE);
jobRecord.setChildGraphGuid(currentRunGUID);
updateSpec.getFinalTransaction().includeJob(jobRecord);
updateSpec.getFinalTransaction().includeBarrier(finalizeBarrier);
backEnd.saveWithJobStateCheck(
updateSpec, jobRecord.getQueueSettings(), jobKey, State.WAITING_TO_RUN, State.RETRY);
}