/** * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { $this->input = $input; $this->output = $output; $passwd = new Passwd(); $users = $passwd->getUsersByGroup($input->getOption("group")); $pools = $this->divideUsersIntoPools($users); $fork = new duncan3dc\Helpers\Fork(); foreach ($pools as $pool) { $fork->call(function () use($pool) { foreach ($pool as $user) { $this->indexFilesForUser($user); } }); } $fork->wait(); }
private function runjobs() { if (!$this->storePath) { $this->storePath = TMP; } // look for a store of the previous run $store = ""; $storeFilePath = $this->storePath . $this->storeFile; if (file_exists($storeFilePath)) { $store = file_get_contents($storeFilePath); } $this->out(date(DATE_SQL) . ' Reading from: ' . $storeFilePath); // build or rebuild the store if ($store != '') { $store = json_decode($store, true); } else { $store = $this->schedule; } App::import('Vendor', 'Fork', array('file' => 'duncan3dc/fork-helper/src/Fork.php')); $fork = new \duncan3dc\Helpers\Fork(); //debug($this->schedule); //debug($store); // run the jobs that need to be run, record the time foreach ($this->schedule as $name => $job) { $now = new DateTime(); $task = $job['task']; $action = $job['action']; // if the job has never been run before, create it if (!isset($store[$name])) { $store[$name] = $job; } // figure out the last run date $tmptime = $store[$name]['lastRun']; if ($tmptime == null) { $tmptime = new DateTime("1969-01-01 00:00:00"); } elseif (is_array($tmptime)) { $tmptime = new DateTime($tmptime['date'], new DateTimeZone($tmptime['timezone'])); } elseif (is_string($tmptime)) { $tmptime = new DateTime($tmptime); } $runNow = false; // determine the next run time based on the last if (substr($job['interval'], 0, 1) === 'P') { $tmptime->add(new DateInterval($job['interval'])); // "P10DT4H" http://www.php.net/manual/en/class.dateinterval.php $runNow = $tmptime <= $now; } elseif (strtotime($job['interval']) !== false) { $tmptime->modify($job['interval']); // "next day 10:30" http://www.php.net/manual/en/datetime.formats.relative.php $runNow = $tmptime <= $now; } else { //cron expression //https://github.com/mtdowling/cron-expression $cron = Cron\CronExpression::factory($job['interval']); $runNow = $cron->getNextRunDate($tmptime) <= $now; $tmptime = $cron->getNextRunDate(); //override for beter log readingz } $this->out('JOB ' . $job['name'] . ' next run time: ' . $tmptime->format(DATE_SQL)); // is it time to run? has it never been run before? //aditionaly, is it currently running if ($runNow && empty($store[$name]['runningPID'])) { $this->out(date(DATE_SQL) . " Running {$name} --------------------------------------- "); if (!isset($this->{$task})) { $this->{$task} = $this->Tasks->load($task); // load models if they aren't already foreach ($this->{$task}->uses as $mk => $mv) { if (!isset($this->{$task}->{$mv})) { App::uses('AppModel', 'Model'); App::uses($mv, 'Model'); $this->{$task}->{$mv} = new $mv(); } } } // grab the entire schedule record incase it was updated.. $store[$name] = $this->schedule[$name]; // execute the task and store the result //$store[$name]['lastResult'] = call_user_func_array(array($this->$task, $action), $job['args']); //$reportInvoicesTask = $this->Tasks->load('ReportInvoices'); //$fork->call(array($reportInvoicesTask,"execute"),array('2014-01-01 00:00:00','2016-01-01 00:00:00',"invoiceDaily")); //$store[$name]['lastResult'] = $fork->call(array($this->$task, $action), $job['args']); $store[$name]['runningPID'] = $fork->call(array($this->{$task}, $action), $job['args']); $this->out(date(DATE_SQL) . " Started {$name} as PID: " . $store[$name]['runningPID']); $this->activeThreads[] = $store[$name]['runningPID']; //unset($reportInvoicesTask); // assign it the current time $now = new DateTime(); $store[$name]['lastRun'] = $now->format('Y-m-d H:i:s'); } } // write the store back to the file file_put_contents($this->storePath . $this->storeFile, json_encode($store)); $this->out(date(DATE_SQL) . ' All pending tasks are no longer pending'); //$runningProcesses=Hash::extract($store,"{s}.runningPID"); //debug($runningProcesses); for ($pcnt = 0; $pcnt < count($this->activeThreads); $pcnt++) { try { $endedPID = $fork->waitAny(); $store = file_get_contents($storeFilePath); $store = json_decode($store, true); foreach ($store as $v) { if ($v['runningPID'] == $endedPID) { $finishedTask = $v; break; } } $this->out(date(DATE_SQL) . " Ended " . $finishedTask['name'] . " as PID: " . $endedPID); $store[$finishedTask['name']]['runningPID'] = null; file_put_contents($this->storePath . $this->storeFile, json_encode($store)); } catch (Exception $e) { $message = $e->getMessage(); $endedPID = $e->getCode(); $store = file_get_contents($storeFilePath); $store = json_decode($store, true); foreach ($store as $v) { if ($v['runningPID'] == $endedPID) { $finishedTask = $v; break; } } $this->out(date(DATE_SQL) . " Ended " . $finishedTask['name'] . " as PID: " . $endedPID . " with EXCEPTION: \n" . $message); $store[$finishedTask['name']]['runningPID'] = null; $store[$finishedTask['name']]['lastResult'] = $message; file_put_contents($this->storePath . $this->storeFile, json_encode($store)); } } }
<?php require 'vendor/autoload.php'; $fork = new \duncan3dc\Helpers\Fork(); $fork->call(function () { for ($i = 1; $i <= 3; $i++) { echo "Process A - " . $i . "\n"; sleep(1); } });
/** * @depends testShouldGetTubes */ public function testShouldDoWork() { if (!class_exists('\\duncan3dc\\Helpers\\Fork')) { $this->markTestSkipped(sprintf('%s used as a dependency \\duncan3dc\\Helpers\\Fork. You can install it by using' . 'composer require "duncan3dc/fork-helper":"*"', get_class($this->client))); } $memory = shmop_open($this->shmKey, 'c', 0644, $this->shmLimit); if (false === $memory) { $this->markTestSkipped('Cannot create shared memory block'); } else { shmop_close($memory); } $expected = ['test-tube-1' => '1', 'test-tube-2' => '2']; $fork = new \duncan3dc\Helpers\Fork(); $fork->call(function () use($expected) { foreach ($expected as $tube => $value) { $this->client->addWorker($tube, function (Job $job) { // Store string "test-tube-%JOB_BODY%" in a shared memory $memory = shmop_open($this->shmKey, 'c', 0644, $this->shmLimit); $output = trim(shmop_read($memory, 0, $this->shmLimit)); $output .= sprintf("\ntest-tube-%s", $job->getBody()); shmop_write($memory, $output, 0); shmop_close($memory); throw new \RuntimeException('Forced exception to stop worker'); }); $this->assertNotEquals(false, $this->client->putInTube($tube, $value)); } $this->client->doWork(); exit(0); }); $reflectionFork = new \ReflectionClass($fork); $reflectionThreads = $reflectionFork->getProperty('threads'); $reflectionThreads->setAccessible(true); sleep(2); $reflectionThreads->setValue($fork, []); unset($fork); $memory = shmop_open($this->shmKey, 'a', 0, 0); $output = shmop_read($memory, 0, $this->shmLimit); $this->assertTrue(shmop_delete($memory)); shmop_close($memory); $this->assertNotEmpty($output); $actual = explode("\n", trim($output)); // Compare number of items in expected list with lines in shared memory $this->assertEquals(count($expected), count($actual)); foreach ($actual as $value) { $this->assertArrayHasKey($value, $expected); } }