/** * starts worker */ public function run() { declare (ticks=1); $this->startup(); $this->who = 'master:' . $this->workerName; $this->logContext = ['type' => $this->who, 'job.identifier' => null]; $this->logger->info('{type}: Worker started', $this->logContext); $this->logger->info('{type}: monitoring the following queues (in order), {queues}', ['type' => $this->who, 'queues' => implode(', ', $this->queues)]); $did_work = false; while (true) { if ($this->shutdown) { $this->logger->info('{type}: Shutting down', $this->logContext); break; } while ($this->paused) { usleep(250000); } if ($did_work) { $this->logger->debug('{type}: Looking for work', $this->logContext); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $this->interval); $did_work = false; } $job = $this->reserve(); if (!$job) { if ($this->interval == 0) { break; } usleep($this->interval * 1000000); continue; } $this->job = $job; $this->logContext['job.identifier'] = $job->getId(); // fork processes $this->childStart(); $this->watchdogStart(); // Parent process, sit and wait $proc_line = 'Forked ' . $this->childPID . ' at ' . strftime('%F %T'); $this->updateProcLine($proc_line); $this->logger->info($proc_line, $this->logContext); while ($this->childProcesses > 0) { $status = null; $pid = pcntl_wait($status, WUNTRACED); if ($pid > 0) { if ($pid === $this->childPID) { $exited = $this->childProcessStatus($status); } else { if ($pid === $this->watchdogPID) { $exited = $this->watchdogProcessStatus($status); } else { // unexpected? $this->logger->info(sprintf("master received status for unknown PID %d; exiting\n", $pid)); exit(1); } } if ($exited) { --$this->childProcesses; switch ($pid) { case $this->childPID: $this->childPID = null; if ($this->watchdogPID) { // shutdown watchdog immediately if child has exited posix_kill($this->watchdogPID, SIGKILL); } break; case $this->watchdogPID: $this->watchdogPID = null; break; } } } } foreach ($this->sockets as $socket) { socket_close($socket); } $this->sockets = []; $this->job = null; $this->logContext['job.identifier'] = null; $did_work = true; /** * We need to reconnect due to bug in Redis library that always sends QUIT on destruction of \Redis * rather than just leaving socket around. This call will sometimes generate a broken pipe notice */ $old = error_reporting(); error_reporting($old & ~E_NOTICE); try { $this->client->reconnect(); } finally { error_reporting($old); } } }