public function primes_among($set) { $this->mediator->log('Looking for primes among ' . count($set) . ' items between ' . min($set) . ' and ' . max($set)); $primes = array(); foreach ($set as $i) { if ($this->is_prime($i)) { $primes[] = $i; } } return $primes; }
/** * Poll the API for updated information -- Simulate an API call of varying duration. * @param Credential $credential * @return void * @throws \ConnectionException */ public function poll(Credential $credential) { $client = new Client($credential, Pdo::createInstance(), new CoreWorkerMediator($this->mediator)); try { while (true) { $client->pollMessages(); $client->sendMessages(); } } catch (\Exception $e) { $this->mediator->log("error: " . $e->getMessage() . "\n" . $e->getTraceAsString()); } }
/** * Poll the API for updated information -- Simulate an API call of varying duration. * @return Array Return associative array of results */ public function poll(array $existing_results) { static $calls = 0; $calls++; $this->results = $existing_results; $this->mediator->log('Calling API...'); // Simulate an API call of varying length $rand = mt_rand(1, 10); switch ($rand) { case 1: $ttl = 4; break; case 2: case 3: $ttl = 8; break; case 8: case 9: $ttl = 16; break; case 10: $ttl = 20; break; default: $ttl = 12; } // Sleep for $ttl seconds to simulate API request time sleep($ttl); // If this is our first call, create initial results if ($calls == 1) { $this->results['customers'] = mt_rand(100, 1000); $this->results['sales'] = $this->results['customers'] * mt_rand(20, 100); return $this->results; } // Increase the stats in our results array accordingly $multiplier = mt_rand(100, 125) / 100; $this->results['customers'] = intval($this->results['customers'] * $multiplier); $this->results['sales'] = intval($this->results['sales'] * $multiplier); return $this->results; }
/** * Handle IPC Errors * @param $error * @param int $try Inform error() of repeated failures of the same $error_code * @return boolean Returns true if the operation should be retried. */ public function error($error, $try = 1) { // Create an array of random, moderate size and verify it can be written to shared memory // Return boolean $that = $this; $test = function () use($that) { $arr = array_fill(0, mt_rand(10, 100), mt_rand(1000, 1000 * 1000)); $key = mt_rand(1000 * 1000, 2000 * 1000); @shm_put_var($that->shm, $key, $arr); usleep(5000); return @shm_get_var($that->shm, $key) == $arr; }; switch ($error) { case 0: // Success // Success case 4: // System Interrupt // System Interrupt case MSG_ENOMSG: // No message of desired type // Ignored Errors return true; break; case MSG_EAGAIN: // Temporary Problem, Try Again usleep($this->mediator->backoff(20000, $try)); return true; break; case 13: // Permission Denied $this->mediator->count_error('communication'); $this->mediator->log('Permission Denied: Cannot connect to message queue'); $this->purge_mq(); if (Core_Daemon::is('parent')) { usleep($this->mediator->backoff(100000, $try)); } else { sleep($this->mediator->backoff(3, $try)); } $this->setup_ipc(); return true; break; case 22: // Invalid Argument // Probably because the queue was removed in another process. // Invalid Argument // Probably because the queue was removed in another process. case 43: // Identifier Removed // A message queue was re-created at this address but the resource identifier we have needs to be re-created $this->mediator->count_error('communication'); if (Core_Daemon::is('parent')) { usleep($this->mediator->backoff(20000, $try)); } else { sleep($this->mediator->backoff(2, $try)); } $this->setup_ipc(); return true; break; case self::ERROR_UNKNOWN: // Almost certainly an issue with shared memory $this->mediator->log("Shared Memory I/O Error at Address {$this->mediator->guid}."); $this->mediator->count_error('corruption'); // If this is a worker, all we can do is try to re-attach the shared memory. // Any corruption or OOM errors will be handled by the parent exclusively. if (!Core_Daemon::is('parent')) { sleep($this->mediator->backoff(3, $try)); $this->setup_ipc(); return true; } // If this is the parent, do some diagnostic checks and attempt correction. usleep($this->mediator->backoff(20000, $try)); // Test writing to shared memory using an array that should come to a few kilobytes. for ($i = 0; $i < 2; $i++) { if ($test()) { return true; } // Re-attach the shared memory and try the diagnostic again $this->setup_ipc(); } $this->mediator->log("IPC DIAG: Re-Connect failed to solve the problem."); if (!$this->mediator->daemon->is('parent')) { break; } // Attempt to re-connect the shared memory // See if we can read what's in shared memory and re-write it later $items_to_copy = array(); $items_to_call = array(); for ($i = 0; $i < $this->mediator->call_count; $i++) { $call = @shm_get_var($this->shm, $i); if (!is_object($call)) { continue; } $cached = $this->mediator->get_struct($i); if (!is_object($cached)) { continue; } if ($cached->status == Core_Worker_Mediator::TIMEOUT) { continue; } if ($cached->status == Core_Worker_Mediator::UNCALLED) { $items_to_call[$i] = $call; continue; } $items_to_copy[$i] = $call; } $this->mediator->log("IPC DIAG: Preparing to clean SHM and Reconnect..."); for ($i = 0; $i < 2; $i++) { $this->purge_shm(); $this->setup_ipc(); if (!empty($items_to_copy)) { foreach ($items_to_copy as $key => $value) { @shm_put_var($this->shm, $key, $value); } } if (!$test()) { if (empty($items_to_copy)) { $this->mediator->fatal_error("Shared Memory Failure: Unable to proceed."); } else { $this->mediator->log('IPC DIAG: Purging items from shared memory: ' . implode(', ', array_keys($items_to_copy))); unset($items_to_copy); } } } foreach ($items_to_call as $call) { $this->mediator->retry($call); } return true; default: if ($error) { $this->mediator->log("Message Queue Error {$error}: " . posix_strerror($error)); } if (Core_Daemon::is('parent')) { usleep($this->mediator->backoff(100000, $try)); } else { sleep($this->mediator->backoff(3, $try)); } $this->mediator->count_error('catchall'); $this->setup_ipc(); return false; } }