putAll(group.getFailureRecords());
}
private boolean transactionallySaveAll(UpdateSpec.Transaction transactionSpec,
QueueSettings queueSettings, Key rootJobKey, Key jobKey, JobRecord.State... expectedStates) {
Transaction transaction = dataStore.beginTransaction();
try {
if (jobKey != null && expectedStates != null) {
Entity entity = null;
try {
entity = dataStore.get(jobKey);
} catch (EntityNotFoundException e) {
throw new RuntimeException(
"Fatal Pipeline corruption error. No JobRecord found with key = " + jobKey);
}
JobRecord jobRecord = new JobRecord(entity);
JobRecord.State state = jobRecord.getState();
boolean stateIsExpected = false;
for (JobRecord.State expectedState : expectedStates) {
if (state == expectedState) {
stateIsExpected = true;
break;
}
}
if (!stateIsExpected) {
logger.info("Job " + jobRecord + " is not in one of the expected states: "
+ Arrays.asList(expectedStates)
+ " and so transactionallySaveAll() will not continue.");
return false;
}
}
saveAll(transactionSpec);
if (transactionSpec instanceof UpdateSpec.TransactionWithTasks) {
UpdateSpec.TransactionWithTasks transactionWithTasks =
(UpdateSpec.TransactionWithTasks) transactionSpec;
Collection<Task> tasks = transactionWithTasks.getTasks();
if (tasks.size() > 0) {
byte[] encodedTasks = FanoutTask.encodeTasks(tasks);
FanoutTaskRecord ftRecord = new FanoutTaskRecord(rootJobKey, encodedTasks);
// Store FanoutTaskRecord outside of any transaction, but before
// the FanoutTask is enqueued. If the put succeeds but the
// enqueue fails then the FanoutTaskRecord is orphaned. But
// the Pipeline is still consistent.
dataStore.put(null, ftRecord.toEntity());
FanoutTask fannoutTask = new FanoutTask(ftRecord.getKey(), queueSettings);
taskQueue.enqueue(fannoutTask);
}
}
transaction.commit();
} finally {
if (transaction.isActive()) {
transaction.rollback();
}
}
return true;
}