public function testRunningDaemonWithResistingWorker() { $writer = $this->getFileWriter(); $fork = $this->outerManager->fork(function () use($writer) { $handler = new NullHandler(); $builder = new Builder(array('worker1' => function () use($writer) { $writer("worker1.call"); }, 'worker2' => array('startup' => function () use($writer) { pcntl_signal(SIGQUIT, SIG_IGN); pcntl_signal(SIGINT, SIG_IGN); $writer("worker2.startup"); }, 'loop' => function () use($writer) { $writer("worker2.call"); }, 'interval' => 1))); $builder->setLogger(new Logger('test', array($handler)))->setShutdownTimeout(3); $daemon = $builder->build(); $daemon->setProcessName('testing'); $daemon->run(); }); sleep(1); $start = time(); $fork->kill(SIGQUIT); while (posix_kill($fork->getPid(), 0)) { pcntl_waitpid($fork->getPid(), $status, WNOHANG | WUNTRACED); usleep(100000); } $end = time(); $diff = $end - $start; $this->assertTrue($diff >= 2 && $diff <= 4, 'Has been killed in shutdown interval'); $content = file_get_contents($this->tempFile); $this->assertSame(1, preg_match_all('/worker1\\.call/', $content)); $this->assertSame(1, preg_match_all('/worker2\\.startup/', $content)); $calls = preg_match_all('/worker2\\.call/', $content); $this->assertTrue($calls >= 3 && $calls <= 5, 'Expected amount of worker2 calls'); }
public function testObjectReturn() { $fork = $this->manager->fork(function () { return new Unserializable(); }); $this->manager->wait(); $this->assertNull($fork->getResult()); $this->assertFalse($fork->isSuccessful()); }
/** * Forks, runs code in the children and wait until all finished. * * @param int $concurrency The amount of forks. * @param callable $code The code for the fork. */ private function fork($concurrency, callable $code) { $manager = new ProcessManager(); for ($i = 0; $i < $concurrency; $i++) { $manager->fork($code); } }
/** * @param Job $job * @return \Spork\Fork */ protected function performJob(Job $job) { $this->host->disconnect(); return $this->spork->fork(function () use($job) { $performer = new JobPerformer($this->host, $job, $this->jobCreator, $this->logger); return $performer->perform(); }); }
/** * Makes sure worker instance is running * * @param Worker $worker */ protected function assureWorkerForkRunning(Worker $worker) { // start now required amount $self =& $this; $name = $worker->getName(); $diff = $worker->getAmount() - $this->countRunning($name); if (!isset($this->forks[$name])) { $this->forks[$name] = array(); } for ($i = 0; $i < $diff; $i++) { $this->event->dispatch(Event::EVENT_WORKER_STARTING, new Event($worker)); $fork = $this->manager->fork(function () use($worker, $self) { $this->currentWorker = $worker; $self->bindWorkerSignals(); if (function_exists('setproctitle')) { setproctitle($worker->getName()); } $startupArgs = array(); if ($worker->hasStartup()) { $startupArgs = $worker->runStartup(); if (!is_array($startupArgs)) { $startupArgs = array($startupArgs); } } $intervals = $worker->getInterval() * 10; while (true) { $worker->run($startupArgs); for ($i = 0; $i < $intervals; $i++) { Builtin::doUsleep(100000); if ($self->stopped) { $this->event->dispatch(Event::EVENT_WORKER_STOPPED, new Event($this->currentWorker)); break 2; } } } })->then(function (Fork $fork) use($name, $self) { unset($self->forks[$fork->getPid()][$name]); }); $this->forks[$name][$fork->getPid()] = $fork; $this->event->dispatch(Event::EVENT_WORKER_STARTED, new Event($worker), array($fork)); } }
/** * Tests seeding produces different tokens for each process. * * @test */ public function testSeedRandom() { $mutex = $this->buildRedisMutex(1); $mutex->seedRandom(); $tokens = []; $processManager = new ProcessManager(); for ($i = 0; $i < 2; $i++) { $processManager->fork(function () { $mutex = $this->buildRedisMutex(1); $mutex->expects($this->any())->method("evalScript")->willReturn(true); $token = null; $mutex->expects($this->any())->method("add")->willReturnCallback(function ($redisAPI, $key, $value, $expire) use(&$token) { $token = "{$value}"; return true; }); $mutex->synchronized(function () { }); return $token; })->then(function (Fork $fork) use(&$tokens) { $this->assertArrayNotHasKey($fork->getResult(), $tokens); $tokens[$fork->getResult()] = $fork->getResult(); }); } }
/** * Tests that locks will be released automatically. * * @param callable $mutexFactory The Mutex factory. * @test * @dataProvider provideMutexFactories */ public function testLiveness(callable $mutexFactory) { $manager = new ProcessManager(); $manager->fork(function () use($mutexFactory) { $mutex = call_user_func($mutexFactory); $mutex->synchronized(function () { exit; }); }); $manager->wait(); sleep(self::TIMEOUT - 1); $mutex = call_user_func($mutexFactory); $mutex->synchronized(function () { }); }