private function runTask(TaskInterface $task, PayloadInterface $payload)
    {
        $this->logTask($task, LogLevel::INFO, 'Starting execution.');

        try {
            if (!$task->unless()) {
                $this->dispatch('runner.task.unless', $task, $payload);
                $this->logTask($task, LogLevel::INFO, 'Skipping because unless() returned boolean false.');
                return;
            }

            $this->dispatch('runner.task.start', $task, $payload);

            $task->setUp();
            $exitCode = (int)$task->run($payload) ?: 0;
            $task->tearDown();

            if ($task->isFailOnError() && $exitCode !== 0) {
                throw new FailException(
                    sprintf(
                        'Task: %s failed with exit code %s',
                        get_class($task),
                        $exitCode
                    )
                );
            }

            $message = sprintf('Task exited with status code %s', $exitCode);
            if ($exitCode === 0) {
                $this->logTask($task, LogLevel::INFO, $message);
            } else {
                $this->logTask($task, LogLevel::WARNING, $message);
            }

            $this->dispatch('runner.task.success', $task, $payload, $exitCode);
            $task->markAsSuccessfullyExecuted();
        } catch (SkipException $e) {
            $this->logTask($task, LogLevel::INFO, 'Skipping.');
            $this->dispatch('runner.task.skip', $task, $payload);
        } catch (RetryException $e) {
            $this->logTask($task, LogLevel::NOTICE, 'Retry thrown. Starting again.');
            $this->dispatch('runner.task.retry', $task, $payload);
            if (!$task->getMaxRetries()) {
                throw new LogicException('A retry exception was thrown, but no retries instance was set.');
            }
            $task->getMaxRetries()->increase();
            $this->runTask($task, $payload);
            return;
        } catch (FailException $e) {
            $this->logTask(
                $task,
                LogLevel::WARNING,
                sprintf(
                    'Failure thrown. Given message: %s',
                    $e->getMessage()
                )
            );

            $exitCode = $e->getCode();
            if (is_int($exitCode)) {
                $this->dispatch('runner.task.failure', $task, $payload, $exitCode);
            } else {
                $this->dispatch('runner.task.failure', $task, $payload);
            }

            throw $e;
        }

        $this->logTask($task, LogLevel::INFO, 'Execution successful.');
    }