taskStorage = $taskStorage; Events::addListener([$this, 'fatalHandler'], 'haltExecutionEvent', Priority::HIGH); } /** * Run a task by finding its ID * * @param string $taskId * @param bool $post * @throws EventException * @throws TasksException */ public function runTaskById(string $taskId, bool $post = false) { // First fetch the task try { $task = $this->taskStorage->getTaskById($taskId); } catch (TasksException $e) { throw new TasksException("Could not run worker. Task not found."); } $this->run($task, $post); } /** * @param Task $task * @param bool $post * @throws EventException * @throws TasksException */ public function run(Task $task, bool $post = false) { // Fire a taskHandleEvent /** @var TaskHandleEvent $event */ $event = Events::fireEvent(new TaskHandleEvent(), $task); // Set task to this worker $this->task = $event->getTask(); $this->post = $post; // Fetch the callable $handler = $this->task->getHandler(); // Execute the handler and all its parent handlers $success = $this->executeHandler($this->task, $handler, $post); // Fetch the output and errors $output = $post ? $handler->getPostOutput() : $handler->getOutput(); $output = is_null($output) ? '' : $output; $errors = $this->getErrors(); // If the task failed, write so to task storage, based on whether this is a post request or not if (!$success && $post) $this->taskStorage->writePostOutput($this->task, $output, $errors, Task::FAILED); elseif (!$success && !$post) $this->taskStorage->writeTaskOutput($this->task, $output, $errors, Task::FAILED); elseif ($success && $post) $this->taskStorage->writePostOutput($this->task, $output, $errors, Task::SUCCESS); else $this->taskStorage->writeTaskOutput($this->task, $output, $errors, Task::SUCCESS); // And write the final output $this->output((string) $output, $errors); } protected function executeHandler(Task $task, Handler $handler, bool $usePost = false): bool { // First check to see if there is a parent handler $parent = $handler->getParentHandler(); if (!is_null($parent)) { // Execute the parent if ($this->executeHandler($task, $parent, $usePost) === false) return false; // Fetch the output of the parent $output = $usePost ? $parent->getPostOutput() : $parent->getOutput(); // And insert it as input into the child handler $handler->setParentInput($output); } return $usePost ? $handler->postHandler($task) : $handler->primaryHandler($task); } /** * In case a fatal error or exception occurs, the errors shall be redirected to stderr * * @param HaltExecutionEvent $event */ public function fatalHandler(HaltExecutionEvent $event) { // Cancel further execution by FuzeWorks $event->setCancelled(true); // Collect all error logs $errors = $this->getErrors(); $this->output('', $errors); // If no task is set yet, abort error logging to task if (is_null($this->task)) return; try { // Write to TaskStorage if (!$this->post) $this->taskStorage->writeTaskOutput($this->task, '', $errors, Task::FAILED); else $this->taskStorage->writePostOutput($this->task, '', $errors, Task::FAILED); } catch (TasksException $e) { // Ignore } exit; } /** * Get all errors, exceptions and warnings from runtime and turn them into a string * * @return string */ protected function getErrors(): string { $output = []; foreach (Logger::$logs as $log) { if ($log['type'] !== 'ERROR' && $log['type'] !== 'EXCEPTION' && $log['type'] !== 'WARNING') continue; $output[] = strtoupper($log['type']) . ' ' . (!empty($log['logFile']) && !empty($log['logLine']) ? $log['logFile'] . ':' . $log['logLine'] . " '" : "'") . $log['message'] . "'"; } return implode("\n", $output); } /** * Output the results to stdout and stderr * * @param string $output * @param string $errors */ protected function output(string $output, string $errors) { // First write to stderr if (!empty($errors)) fwrite(STDERR, $errors . PHP_EOL); // Afterwards write to stdout if (!empty($output)) echo $output . PHP_EOL; } }