protected function MaestroEngine::nextStep in Maestro 3.x
Same name and namespace in other branches
- 8.2 src/Engine/MaestroEngine.php \Drupal\maestro\Engine\MaestroEngine::nextStep()
NextStep Engine method that determines which is the next step based on the current step and does all assignments as necessary.
Parameters
string $template: The Maestro template.
string $templateTaskID: The machine name of the task.
int $processID: The Maestro Process ID.
int $completionStatus: The completion status being set. Definitions found in maestro.module.
1 call to MaestroEngine::nextStep()
- MaestroEngine::cleanQueue in src/
Engine/ MaestroEngine.php - CleanQueue method This is the core method used by the orchestrator to move the process forward and to determine assignments and next steps.
File
- src/
Engine/ MaestroEngine.php, line 1546
Class
- MaestroEngine
- Class MaestroEngine.
Namespace
Drupal\maestro\EngineCode
protected function nextStep($template, $templateTaskID, $processID, $completionStatus) {
$templateTask = $this
->getTemplateTaskByID($template, $templateTaskID);
$regenerationFlag = FALSE;
// Nextstep or nextfalsestep is a comma separated string of next task machine names to point to.
$nextSteps = $templateTask['nextstep'];
// Completion status tells us to point to the false branch.
if ($completionStatus == MAESTRO_TASK_COMPLETION_USE_FALSE_BRANCH) {
$nextSteps = $templateTask['nextfalsestep'];
}
// TODO: In the event we have a feature request for extra completion status codes, at this point we've established the core Maestro status codes and,
// have altered the next steps to respect the IF task scenario.
// Is there really any other scenario? We've never come across this issue. But this would be the spot in-code to allow for a
// module invocation to alter the next steps based on completion status.
if ($nextSteps != '') {
$taskArray = explode(',', $nextSteps);
foreach ($taskArray as $taskID) {
// Determine if this task is already present in this instance of the queue/process combo
// but first, determine if they're trying to recreate a task that has already been completed
// this is our chance to do an auto-regeneration
// we also filter for the tasks not being an OR or AND task.
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
// Race condition? what if its complete and not archived, yet a loopback happens? Leave for now.
$query
->condition('archived', TASK_ARCHIVE_REGEN, '<>')
->condition('status', TASK_STATUS_ACTIVE, '<>')
->condition('process_id', $processID)
->condition('task_id', $taskID)
->condition('task_class_name', 'MaestroOr', '<>')
->condition('task_class_name', 'MaestroAnd', '<>');
$entity_ids = $query
->execute();
if (count($entity_ids) == 0) {
// No regeneration! this is a straightforward engine carry-on condition
// in Drupal 7's engine, we had flags to check to see if a task REEEEEEALY wanted to be regenerated.
// no more. After 10 years of engine development, we've found that regeneration of all in-prod tasks is the way to go
// look at the ELSE clause to see the regen.
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
// We don't need to recreate if this thing is already in the queue.
$query
->condition('archived', '0')
->condition('status', TASK_STATUS_ACTIVE)
->condition('process_id', $processID)
->condition('task_id', $taskID);
$entity_ids = $query
->execute();
// Means we haven't already created it in this process. avoids mimicking the regen issue.
if (count($entity_ids) == 0) {
$queueID = $this
->createProductionTask($taskID, $template, $processID);
}
}
else {
// It is in this area where we are doing a complete loopback over our existing template
// after years of development experience and creating many business logic templates, we've found that
// the overwhelming majority (like 99%) of all templates really do a regeneration of all
// in-production tasks and that people really do want to do a regeneration.
// Thus the regen flags have been omitted. Now we just handle everything with status flags and keep the same
// process ID.
// The biggest issue are the AND tasks. We need to know which tasks the AND has pointing to it and keep those
// tasks hanging around in the queue in either a completed and archived state or in their fully open, executable state.
// so we have to first find all AND tasks, and then determine who points to them and leave their archive condition alone.
$noRegenStatusArray = [];
// So first, search for open AND tasks:
// Race condition? what if its complete and not archived, yet a loopback happens? Leave for now.
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('archived', '1')
->condition('status', '0')
->condition('process_id', $processID)
->condition('task_class_name', 'MaestroAnd');
// Going to use these IDs to determine who points to them.
$andIDs = $query
->execute();
if (is_array($andIDs)) {
$noRegenStatusArray += $andIDs;
}
foreach ($andIDs as $entityID) {
// Load the entity from the queue.
$queueRecord = MaestroEngine::getQueueEntryById($entityID);
$pointers = MaestroEngine::getTaskPointersFromTemplate(MaestroEngine::getTemplateIdFromProcessId($processID), $queueRecord->task_id
->getValue());
// Now we query the queue to add the pointers to the noRegenStatusArray.
$query = \Drupal::entityQuery('maestro_queue')
->accessCheck(FALSE);
$andMainConditions = $query
->andConditionGroup()
->condition('process_id', $processID);
$orConditionGroup = $query
->orConditionGroup();
foreach ($pointers as $taskID) {
$orConditionGroup
->condition('task_id', $taskID);
}
$andMainConditions
->condition($orConditionGroup);
$query
->condition($andMainConditions);
$pointerIDs = $query
->execute();
if (is_array($pointerIDs)) {
// Add the entity IDs to the tasks that point to the AND as those that shouldn't be flagged.
$noRegenStatusArray += $pointerIDs;
}
}
// now, we have a list of noRegenStatusArray which are entity IDs in the maestro_queue for which we do NOT change the archive flag for.
$query = \Drupal::entityTypeManager()
->getStorage('maestro_queue')
->getQuery();
$query
->condition('status', '0', '<>')
->condition('process_id', $processID);
$regenIDs = $query
->execute();
foreach ($regenIDs as $entityID) {
// Set this queue record to regenerated IF it doesn't exist in the noRegenStatusArray.
if (array_search($entityID, $noRegenStatusArray) === FALSE) {
$queueRecord = MaestroEngine::getQueueEntryById($entityID);
$queueRecord
->set('archived', TASK_ARCHIVE_REGEN);
$queueRecord
->save();
}
}
// And now we create the task being looped back over to:
$queueID = $this
->createProductionTask($taskID, $template, $processID);
}
}
//end foreach next task
}
else {
// This is the condition where there isn't a next step listed in the task
// this doesn't necessarily suggest an end of process though, as that's what
// the end task is meant for. However, we have a situation here where
// the task doesn't specify a next task. Perhaps this is legitimately the end
// of a task chain while other parallel tasks continue to execute.
// We will consider this a NOOP condition and do nothing.
}
}