public function executeJob($job, $oneTime = false, $passdArguments = array())
{
$id = $job->getId();
$name = $job->getName();
$output = $this->output;
$now = new \DateTime();
if ($output->isDebug()) {
$output->writeln("[debug] Try running a job: {$name} at " . $now->format('Y-m-d H:i:s'));
}
$pid = pcntl_fork();
if ($pid === -1) {
// Error
throw new \RuntimeException("pcntl_fork error.");
} elseif ($pid) {
// Parent process
$status = null;
$pid = pcntl_wait($status);
if (!$pid) {
throw new \RuntimeException("pcntl_wait error.");
}
$job->setLastRunTime($now);
// add next timer
if ($job->hasCronTime() && !$oneTime) {
$this->addJobTimer($job);
}
} else {
// Child process
// Remove tty to ignore signals from tty.
posix_setsid();
// Stops copied event loop.
$this->eventLoop->stop();
unset($this->eventLoop);
$this->dispatcher->dispatch(JobEvents::FORKED_PROCESS, new JobForkedProcessEvent($this->worker, $job));
// Forks it one more time to prevent to be zombie process.
$pid = pcntl_fork();
if ($pid === -1) {
// Error
throw new \RuntimeException("pcntl_fork error.");
} elseif ($pid) {
exit;
}
if ($output->isDebug()) {
$output->writeln("[debug] Forked process for: {$name} (pid:" . posix_getpid() . ")");
}
if ($job->isLimitOfProcesses()) {
$output->writeln("<fg=magenta>Skip the job '{$name}' due to limit of max processes: " . $job->getMaxProcesses() . " at " . (new \DateTime())->format('Y-m-d H:i:s') . "</fg=magenta>");
exit;
}
$output->writeln("<info>Runs job:</info> <comment>{$name}</comment> (pid: " . posix_getpid() . ") at " . (new \DateTime())->format('Y-m-d H:i:s'));
$job->addRuntimeEntryToJobInfo($pid);
$command = $job->getCommand();
if ($command instanceof \Closure) {
// command is a closure
$arguments = array();
$parameters = $job->getCommandParameters();
if ($parameters) {
foreach ($parameters as $parameter) {
$class = $parameter->getClass();
if ($class && $class->getName() === 'Kohkimakimoto\\Worker\\Worker') {
$arguments[] = $this->worker;
continue;
}
$argName = $parameter->getName();
if (isset($passdArguments[$argName])) {
$arguments[] = $passdArguments[$argName];
} else {
$isOptional = $parameter->isOptional();
if (!$isOptional) {
$arguments[] = null;
}
}
}
}
call_user_func_array($command, $arguments);
} elseif (is_string($command)) {
// command is a string
$process = new Process($command);
$process->setTimeout(null);
$process->run(function ($type, $buffer) use($output) {
$output->write($buffer);
});
} else {
throw new \RuntimeException("Unsupported operation.");
}
$job->deleteRuntimeEntryToJobInfo($pid);
$output->writeln("<info>Finished job:</info> <comment>{$name}</comment> (pid: " . posix_getpid() . ") at " . (new \DateTime())->format('Y-m-d H:i:s'));
exit;
}
}