Manager/ProcessManager.php
protected function process(TaskConfiguration $taskConfiguration, int $executionFlag = self::EXECUTE_PROCESS): void
    {
        $this->taskConfiguration = $taskConfiguration;

        $state = $taskConfiguration->getState();
        do {
            // Execute the current task, and fetch status
            $this->processExecution($taskConfiguration, $executionFlag);

            $this->handleState($state);
            if ($state->isStopped()) {
                return;
            }

            // An error feed cannot be blocked or skipped (except if the process has been stopped)
            if ($state->hasErrorOutput()) {
                foreach ($taskConfiguration->getErrorTasksConfigurations() as $errorTask) {
                    $this->prepareNextProcess($taskConfiguration, $errorTask, true);
                    $this->process($errorTask);

                    // Bubble up the stop signal
                    if ($errorTask->getState()->isStopped()) {
                        $state->setStopped(true);

                        return;
                    }
                }
            }

            // Run child items only if the state is not "skipped" and task is not blocking
            $task = $taskConfiguration->getTask();
            $shouldContinue =
                (!$task instanceof BlockingTaskInterface || self::EXECUTE_PROCEED === $executionFlag)
                && !$state->isSkipped();

            if ($shouldContinue) {
                if ($task instanceof IterableTaskInterface) {
                    // Register the task as not empty
                    $this->addProcessedIterable($taskConfiguration);
                }
                foreach ($taskConfiguration->getNextTasksConfigurations() as $nextTaskConfiguration) {
                    $this->prepareNextProcess($taskConfiguration, $nextTaskConfiguration);
                    $this->process($nextTaskConfiguration);

                    // Bubble up the stop signal
                    if ($nextTaskConfiguration->getState()->isStopped()) {
                        $state->setStopped(true);

                        return;
                    }
                }
                $state->setSkipped(false); // Reset skipped state
            }

            $hasMoreItem = false; // By default, a task is not iterable
            if ($task instanceof IterableTaskInterface) {
                // Check if task has more items
                $hasMoreItem = $task->next($state);
                if (!$hasMoreItem) {
                    if (!$this->hasProcessedIterable($taskConfiguration)) {
                        return; // This means the task is empty
                    }
                    // This means we are over iterating this task so we can remove it from registry
                    $this->removeProcessedIterable($taskConfiguration);
                    if ($state->isStopped()) {
                        return;
                    }
                }
            }
        } while ($hasMoreItem);

        $this->taskConfiguration = null;
    }
protected function process(TaskConfiguration $taskConfiguration, int $executionFlag = self::EXECUTE_PROCESS): void
    {
        $this->taskConfiguration = $taskConfiguration;

        $state = $taskConfiguration->getState();
        do {
            // Execute the current task, and fetch status
            $this->processExecution($taskConfiguration, $executionFlag);

            $this->handleState($state);
            if ($state->isStopped()) {
                return;
            }

            // An error feed cannot be blocked or skipped (except if the process has been stopped)
            if ($state->hasErrorOutput()) {
                foreach ($taskConfiguration->getErrorTasksConfigurations() as $errorTask) {
                    $this->prepareNextProcess($taskConfiguration, $errorTask, true);
                    $this->process($errorTask);

                    // Bubble up the stop signal
                    if ($errorTask->getState()->isStopped()) {
                        $state->setStopped(true);

                        return;
                    }
                }
            }

            // Run child items only if the state is not "skipped" and task is not blocking
            $task = $taskConfiguration->getTask();
            $shouldContinue =
                (!$task instanceof BlockingTaskInterface || self::EXECUTE_PROCEED === $executionFlag)
                && !$state->isSkipped();

            if ($shouldContinue) {
                if ($task instanceof IterableTaskInterface) {
                    // Register the task as not empty
                    $this->addProcessedIterable($taskConfiguration);
                }
                foreach ($taskConfiguration->getNextTasksConfigurations() as $nextTaskConfiguration) {
                    $this->prepareNextProcess($taskConfiguration, $nextTaskConfiguration);
                    $this->process($nextTaskConfiguration);

                    // Bubble up the stop signal
                    if ($nextTaskConfiguration->getState()->isStopped()) {
                        $state->setStopped(true);

                        return;
                    }
                }
                $state->setSkipped(false); // Reset skipped state
            }

            $hasMoreItem = false; // By default, a task is not iterable
            if ($task instanceof IterableTaskInterface) {
                // Check if task has more items
                $hasMoreItem = $task->next($state);
                if (!$hasMoreItem) {
                    if (!$this->hasProcessedIterable($taskConfiguration)) {
                        return; // This means the task is empty
                    }
                    // This means we are over iterating this task so we can remove it from registry
                    $this->removeProcessedIterable($taskConfiguration);
                    if ($state->isStopped()) {
                        return;
                    }
                }
            }
        } while ($hasMoreItem);

        $this->taskConfiguration = null;
    }
@param TaskConfiguration $taskConfiguration
@param int               $executionFlag

@throws \RuntimeException