function client_thread($self) { $context = new ZMQContext(); $client = new ZMQSocket($context, ZMQ::SOCKET_REQ); $endpoint = sprintf("ipc://%s-localfe.ipc", $self); $client->connect($endpoint); $monitor = new ZMQSocket($context, ZMQ::SOCKET_PUSH); $endpoint = sprintf("ipc://%s-monitor.ipc", $self); $monitor->connect($endpoint); $readable = $writeable = array(); while (true) { sleep(mt_rand(0, 4)); $burst = mt_rand(1, 14); while ($burst--) { // Send request with random hex ID $task_id = sprintf("%04X", mt_rand(0, 10000)); $client->send($task_id); // Wait max ten seconds for a reply, then complain $poll = new ZMQPoll(); $poll->add($client, ZMQ::POLL_IN); $events = $poll->poll($readable, $writeable, 10 * 1000000); if ($events > 0) { foreach ($readable as $socket) { $zmsg = new Zmsg($socket); $zmsg->recv(); // Worker is supposed to answer us with our task id assert($zmsg->body() == $task_id); } } else { $monitor->send(sprintf("E: CLIENT EXIT - lost task %s", $task_id)); exit; } } } }
/** * Start to poll for events * @throws \Exception */ protected function poll() { if (!$this->poll) { throw new \Exception("Pool doesn't initialized"); } $this->isPolling = true; $read = $write = []; while ($this->isPolling) { $events = $this->poll->poll($read, $write, $this->pollTimeOut); $this->onPoll($events, $read, $write); } }
public static function dispatch($timeout = self::DEFAULT_TIMEOUT) { $origin_timeout = $timeout; $poll = new \ZMQPoll(); foreach (self::$sockets as $socket) { $poll->add($socket, ZMQ::POLL_IN); } $read = $write = array(); while (count(self::$pendingRequests) > 0) { $_start = microtime(true); $events = $poll->poll($read, $write, self::INTERVAL); if ($events > 0) { foreach ($read as $socket) { $recv = $socket->recvMulti(); $event = Response::deserialize($recv); self::handleEvent($event); } } $_end = microtime(true); $timeout -= ($_end - $_start) * 1000; if ($timeout < 0) { break; } } if (count(self::$pendingRequests) > 0) { $exception = count(self::$pendingRequests) . " requests timeout after {$origin_timeout} ms:\n"; foreach (self::$pendingRequests as $id => $pending) { $exception .= " # {$pending['event']->name}\n"; } throw new TimeoutException(trim($exception, "\n")); } $poll->clear(); self::clear(); }
function broker_task() { // Prepare our context and sockets $context = new ZMQContext(); $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $backend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $frontend->bind("tcp://*:5555"); $backend->bind("tcp://*:5556"); // Initialize poll set $poll = new ZMQPoll(); $poll->add($frontend, ZMQ::POLL_IN); $poll->add($backend, ZMQ::POLL_IN); $read = $write = array(); while (true) { $events = $poll->poll($read, $write); foreach ($read as $socket) { $zmsg = new Zmsg($socket); $zmsg->recv(); if ($socket === $frontend) { $zmsg->push("W"); $zmsg->set_socket($backend)->send(); } elseif ($socket === $backend) { $zmsg->pop(); $zmsg->push("C"); $zmsg->set_socket($frontend)->send(); } } } }
/** * @param string $request */ public function request($request) { // Prefix request with sequence number and empty envelope $this->sequence++; $msg = array('', $this->sequence, $request); // Blast the request to all connected servers for ($server = 1; $server <= $this->servers; $server++) { $this->socket->sendMulti($msg); } // Wait for a matching reply to arrive from anywhere // Since we can poll several times, calculate each one $poll = new ZMQPoll(); $poll->add($this->socket, ZMQ::POLL_IN); $reply = null; $endtime = time() + self::GLOBAL_TIMEOUT / 1000; while (time() < $endtime) { $readable = $writable = array(); $events = $poll->poll($readable, $writable, ($endtime - time()) * 1000); foreach ($readable as $sock) { if ($sock == $this->socket) { $reply = $this->socket->recvMulti(); if (count($reply) != 3) { exit; } $sequence = $reply[1]; if ($sequence == $this->sequence) { break; } } } } return $reply; }
/** * Main processing loop * * @throws \ZMQPollException */ public function run() { $poll = new \ZMQPoll(); $readable = $writable = []; foreach ($this->listen as $socket) { $poll->add($socket, \ZMQ::POLL_IN); } $processing = true; Event::listen('zeroevents.service.stop', function () use(&$processing) { $processing = false; }); while ($processing) { try { $poll->poll($readable, $writable, $this->pollTimeout); foreach ($readable as $socket) { $socket->pullAndFire(); } } catch (\ZMQPollException $ex) { if ($ex->getCode() == 4) { // 4 == EINTR, interrupted system call usleep(1); // Don't just continue, otherwise the ticks function won't be processed continue; } throw $ex; } if (!$readable) { Event::fire('zeroevents.service.idle', $this); } } }
/** * @param $receiver */ public function emptyPoll($receiver) { $poll = new \ZMQPoll(); $poll->add($receiver, \ZMQ::POLL_IN); $readable = $writable = array(); $poll->poll($readable, $writable, 0); // Timeout immediately. }
protected function pollForOutput(ObserverInterface $observer, $previous) { $poll = new \ZMQPoll(); $read = $write = []; $poll->add($this->socket->getSocket(), \ZMQ::POLL_OUT); for ($i = 0; $i < 1000; $i += 1) { $events = $poll->poll($read, $write, 1); if ($events) { $observer->onNext($previous); return $observer->onCompleted(); } $this->loop->tick(); } return $observer->onError(new ConnectException("Socket is not answering")); }
protected function _processingLoop() { $poll = new \ZMQPoll(); $poll->add($this->_socketToQueueManager, \ZMQ::POLL_IN); $pollTimeout = $this->_config->get('worker.pollTimeout'); while (true) { $readable = $writable = array(); $events = $poll->poll($readable, $writable, $pollTimeout); if ($events) { foreach ($readable as $socket) { $zmsg = new Zmsg($socket); $zmsg->recv(); $msg = unserialize($zmsg->body()); if ($msg instanceof \Daemon\Message\Shutdown) { $this->log('received shutdown message'); $this->_initShutdown(); return; } try { /** @var $task \Daemon\Task\AbstractTask */ $task = $msg->task; $this->_currentTask = $task; $this->log('starting to execute %s', get_class($task)); $task->setContext($this->_context); $task->setConfig($this->_config); $task->setProcess($this); $task->run(); $this->_currentTask = null; $this->log('execution of %s finished', get_class($task)); $response = new Message\Task\Finished(array('task' => $task, 'workerAddress' => $this->_identity)); $this->_responseToQueueManager($zmsg, $response); if ($task->hasMessagesToQueueManager()) { $responseMessages = $task->getMessagesToQueueManager(); foreach ($responseMessages as $responseMessage) { $this->_responseToQueueManager($zmsg, $responseMessage); } } } catch (\Exception $e) { $response = new Message\Task\Failed(array('task' => $task, 'exception' => $e, 'workerAddress' => $this->_identity)); $this->_responseToQueueManager($zmsg, $response); } } } $this->_sendHeartbeat(); } }
function server_task() { // Launch pool of worker threads, precise number is not critical for ($thread_nbr = 0; $thread_nbr < 5; $thread_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { server_worker(); exit; } } $context = new ZMQContext(); // Frontend socket talks to clients over TCP $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $frontend->bind("tcp://*:5570"); // Backend socket talks to workers over ipc $backend = new ZMQSocket($context, ZMQ::SOCKET_DEALER); $backend->bind("ipc://backend"); // Connect backend to frontend via a queue device // We could do this: // $device = new ZMQDevice($frontend, $backend); // But doing it ourselves means we can debug this more easily $read = $write = array(); // Switch messages between frontend and backend while (true) { $poll = new ZMQPoll(); $poll->add($frontend, ZMQ::POLL_IN); $poll->add($backend, ZMQ::POLL_IN); $poll->poll($read, $write); foreach ($read as $socket) { $zmsg = new Zmsg($socket); $zmsg->recv(); if ($socket === $frontend) { //echo "Request from client:"; //echo $zmsg->__toString(); $zmsg->set_socket($backend)->send(); } else { if ($socket === $backend) { //echo "Request from worker:"; //echo $zmsg->__toString(); $zmsg->set_socket($frontend)->send(); } } } } }
public function handlerAction() { try { // setup the ZMQ content so as to avoid issues with conflicts $ctx = new \ZMQContext(); // create a SOCKET_REP server $server = new \ZMQSocket($ctx, \ZMQ::SOCKET_REP); // configure the server socket to not wait at close time // this is intended to minimise the possibility of messages being received and not handled // however as is mentioned in the TODO below they should be handle them explicitly $server->setSockOpt(\ZMQ::SOCKOPT_LINGER, 0); // bind it to tcp on port 5454 $server->bind('tcp://*:5454'); // create a Poll object to enable us to utilize the REQUEST_TIMEOUT functionality $poll = new \ZMQPoll(); $poll->add($server, \ZMQ::POLL_IN); // initialise the read/write buffers for polling $read = $write = array(); // get the time that we start the loop $start = time(); do { // this instruction will wait for a message or the timeout to occur $events = $poll->poll($read, $write, REQUEST_TIMEOUT); // @TODO since exiting the loop will happens after this point a race condition exists // We need to consider solutions that will ensure ALL messages to $server are processed // if the loop will exit after this iteration. // one could check the $events variable as this contains the number of events // however in this situation we only want to process the $read resources and can // just loop through an array (if it is empty nothing will be done) foreach ($read as $socket) { $message = $socket->recv(); $server->send($message . ' World'); } // ensure that even when a message is processed the handler // does not timeout until the REQUEST_TIMEOUT period // has elapsed $active = time() - $start < REQUEST_TIMEOUT / 1000.0; } while ($active); } catch (Exception $e) { // handle the exception // @TODO } // exit the handler die('This handler has timed out'); }
public function sync($name, array $args, $timeout = 0) { if (!$timeout) { $timeout = $this->timeout; } $event = new Request($name, $args); $this->context->hookBeforeSendRequest($event, $this); $this->socket->sendMulti($event->serialize()); $read = $write = array(); $poll = new \ZMQPoll(); $poll->add($this->socket, ZMQ::POLL_IN); $events = $poll->poll($read, $write, $timeout); if ($events) { $recv = $this->socket->recvMulti(); $event = Response::deserialize($recv); return $event->getContent(); } else { throw new TimeoutException('Timout after ' . $this->timeout . ' ms'); } }
/** * This is the main listen and process loop */ public function listen() { $read = $write = array(); // Get and process messages forever or until interrupted while (true) { $poll = new ZMQPoll(); $poll->add($this->socket, ZMQ::POLL_IN); $events = $poll->poll($read, $write, HEARTBEAT_INTERVAL); // Process next input message, if any if ($events) { $zmsg = new Zmsg($this->socket); $zmsg->recv(); if ($this->verbose) { echo "I: received message:", PHP_EOL, $zmsg->__toString(); } $sender = $zmsg->pop(); $empty = $zmsg->pop(); $header = $zmsg->pop(); if ($header == MDPC_CLIENT) { $this->client_process($sender, $zmsg); } else { if ($header == MDPW_WORKER) { $this->worker_process($sender, $zmsg); } else { echo "E: invalid message", PHP_EOL, $zmsg->__toString(); } } } // Disconnect and delete any expired workers // Send heartbeats to idle workers if needed if (microtime(true) > $this->heartbeat_at) { $this->purge_workers(); foreach ($this->workers as $worker) { $this->worker_send($worker, MDPW_HEARTBEAT, NULL, NULL); } $this->heartbeat_at = microtime(true) + HEARTBEAT_INTERVAL / 1000; } } }
/** * */ public function start() { parent::start(); $read = []; $write = []; $loopTimeout = $this->getOption('idle', -1); while (true) { if ($this->hasPendings()) { $events = $this->rwPoll->poll($read, $write, $loopTimeout); } else { $events = $this->rPoll->poll($read, $write, $loopTimeout); } if ($events > 0) { foreach ($read as $socket) { list($source, $message) = $this->receiveFromSocket($socket); try { $result = $this->consume($message, $source); if (null === $result) { $result = new SuccessResult(); } if (!$result instanceof ResultInterface) { $result = new SuccessResult($result); } } catch (\Exception $e) { $this->logConsumeException($e, $source, $message, $socket); $result = new ExceptionResult($e); } if ($this->isSocketTypeWaitingForReply($socket)) { $this->send($source, $result->serialize()); } } foreach ($write as $socket) { $this->sendPendingToSocket($socket); } } else { $this->idle(); } } }
/** * @param ZMQContext $ctx * @param string $endpoint * @param string $request */ function try_request($ctx, $endpoint, $request) { global $request_timeout; printf("I: Trying echo service at %s...\n", $endpoint); $client = $ctx->getSocket(ZMQ::SOCKET_REQ); $client->connect($endpoint); $client->send($request); $poll = new ZMQPoll(); $poll->add($client, ZMQ::POLL_IN); $readable = $writable = array(); $events = $poll->poll($readable, $writable, $request_timeout); $reply = null; foreach ($readable as $sock) { if ($sock == $client) { $reply = $client->recvMulti(); } else { $reply = null; } } $poll->remove($client); $poll = null; $client = null; return $reply; }
$single['out'] = $context->getSocket(ZMQ::SOCKET_PUSH); $multi = array(); $multi['in'] = $context->getSocket(ZMQ::SOCKET_PULL); $multi['out'] = $context->getSocket(ZMQ::SOCKET_PUSH); $single['in']->bind("tcp://0.0.0.0:5000"); $single['out']->bind("tcp://0.0.0.0:5001"); $multi['in']->bind("tcp://0.0.0.0:5002"); $multi['out']->bind("tcp://0.0.0.0:5003"); $poller = new ZMQPoll(); $poller->add($single['in'], ZMQ::POLL_IN); $poller->add($multi['in'], ZMQ::POLL_IN); $events = 0; while (true) { try { $readable = $writeable = []; $events = $poller->poll($readable, $writeable, -1); } catch (Exception $e) { // do nothing } if ($events > 0) { foreach ($readable as $r) { if ($r === $single['in']) { $msg = $r->recv(); $single['out']->send($msg); } else { $msg = $r->recvmulti(); $multi['out']->sendmulti($msg); } } } }
function main() { for ($client_nbr = 0; $client_nbr < NBR_CLIENTS; $client_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { client_thread(); return; } } for ($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { worker_thread(); return; } } $context = new ZMQContext(); $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $backend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $frontend->bind("ipc://frontend.ipc"); $backend->bind("ipc://backend.ipc"); // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers $available_workers = 0; $worker_queue = array(); $writeable = $readable = array(); while ($client_nbr > 0) { $poll = new ZMQPoll(); // Poll front-end only if we have available workers if ($available_workers > 0) { $poll->add($frontend, ZMQ::POLL_IN); } // Always poll for worker activity on backend $poll->add($backend, ZMQ::POLL_IN); $events = $poll->poll($readable, $writeable); if ($events > 0) { foreach ($readable as $socket) { // Handle worker activity on backend if ($socket === $backend) { // Queue worker address for LRU routing $worker_addr = $socket->recv(); assert($available_workers < NBR_WORKERS); $available_workers++; array_push($worker_queue, $worker_addr); // Second frame is empty $empty = $socket->recv(); assert(empty($empty)); // Third frame is READY or else a client reply address $client_addr = $socket->recv(); if ($client_addr != "READY") { $empty = $socket->recv(); assert(empty($empty)); $reply = $socket->recv(); $frontend->send($client_addr, ZMQ::MODE_SNDMORE); $frontend->send("", ZMQ::MODE_SNDMORE); $frontend->send($reply); // exit after all messages relayed $client_nbr--; } } elseif ($socket === $frontend) { // Now get next client request, route to LRU worker // Client request is [address][empty][request] $client_addr = $socket->recv(); $empty = $socket->recv(); assert(empty($empty)); $request = $socket->recv(); $backend->send(array_shift($worker_queue), ZMQ::MODE_SNDMORE); $backend->send("", ZMQ::MODE_SNDMORE); $backend->send($client_addr, ZMQ::MODE_SNDMORE); $backend->send("", ZMQ::MODE_SNDMORE); $backend->send($request); $available_workers--; } } } } // Clean up our worker processes foreach ($worker_queue as $worker) { $backend->send($worker, ZMQ::MODE_SNDMORE); $backend->send("", ZMQ::MODE_SNDMORE); $backend->send('END'); } sleep(1); }
/** * Send reply, if any, to broker and wait for next request. * * @param Zmsg $reply * @return Zmsg Returns if there is a request to process */ public function recv($reply = null) { // Format and send the reply if we were provided one assert($reply || !$this->expect_reply); if ($reply) { $reply->wrap($this->reply_to); $this->send_to_broker(MDPW_REPLY, NULL, $reply); } $this->expect_reply = true; $read = $write = array(); while (true) { $poll = new ZMQPoll(); $poll->add($this->worker, ZMQ::POLL_IN); $events = $poll->poll($read, $write, $this->heartbeat); if ($events) { $zmsg = new Zmsg($this->worker); $zmsg->recv(); if ($this->verbose) { echo "I: received message from broker:", PHP_EOL; echo $zmsg->__toString(); } $this->liveness = HEARTBEAT_LIVENESS; // Don't try to handle errors, just assert noisily assert($zmsg->parts() >= 3); $zmsg->pop(); $header = $zmsg->pop(); assert($header == MDPW_WORKER); $command = $zmsg->pop(); if ($command == MDPW_REQUEST) { // We should pop and save as many addresses as there are // up to a null part, but for now, just save one... $this->reply_to = $zmsg->unwrap(); return $zmsg; // We have a request to process } else { if ($command == MDPW_HEARTBEAT) { // Do nothing for heartbeats } else { if ($command == MDPW_DISCONNECT) { $this->connect_to_broker(); } else { echo "E: invalid input message", PHP_EOL; echo $zmsg->__toString(); } } } } else { if (--$this->liveness == 0) { // poll ended on timeout, $event being false if ($this->verbose) { echo "W: disconnected from broker - retrying...", PHP_EOL; } usleep($this->reconnect * 1000); $this->connect_to_broker(); } } // Send HEARTBEAT if it's time if (microtime(true) > $this->heartbeat_at) { $this->send_to_broker(MDPW_HEARTBEAT, NULL, NULL); $this->heartbeat_at = microtime(true) + $this->heartbeat / 1000; } } }
$frontend->bind("tcp://*:5555"); // For clients $backend->bind("tcp://*:5556"); // For workers // Queue of available workers $available_workers = 0; $worker_queue = array(); $read = $write = array(); while (true) { $poll = new ZMQPoll(); $poll->add($backend, ZMQ::POLL_IN); // Poll frontend only if we have available workers if ($available_workers) { $poll->add($frontend, ZMQ::POLL_IN); } $events = $poll->poll($read, $write); foreach ($read as $socket) { $zmsg = new Zmsg($socket); $zmsg->recv(); // Handle worker activity on backend if ($socket === $backend) { // Use worker address for LRU routing assert($available_workers < MAX_WORKERS); array_push($worker_queue, $zmsg->unwrap()); $available_workers++; // Return reply to client if it's not a READY if ($zmsg->address() != "READY") { $zmsg->set_socket($frontend)->send(); } } elseif ($socket === $frontend) { // Now get next client request, route to next worker
public function run($task, $payload, $encode = true, $timeout = -1) { // Ensure a valid socket exist for this task if ($this->connectTask($task) === false) { return null; } if ($encode) { $payload = json_encode($payload); } // Send the message to the Task $mess = sprintf('%s %s %s', $task, $this->id, $payload); try { self::$sockets[$task]->send($mess, \ZMQ::MODE_NOBLOCK); } catch (\ZMQSocketException $e) { $this->disconnectTask($task); return null; } if ('async' === self::$types[$task]) { return true; } // Wait the answer $poll = new \ZMQPoll(); $poll->add(self::$sockets[$task], \ZMQ::POLL_IN); if ($timeout !== -1) { $timeout = $timeout * 1000; // Convert timeout from seconds to ms } $to_read = $to_write = array(); try { $events = $poll->poll($to_read, $to_write, $timeout); $errors = $poll->getLastErrors(); if (count($errors) > 0) { foreach ($errors as $error) { Log::error('Error polling object: ' . $error); } } } catch (\ZMQPollException $e) { Log::fatal('Poll failed: ' . $e->getMessage()); $this->disconnectTask($task); return null; } // An answer has been received if ($events > 0) { list(, , $res) = explode(' ', self::$sockets[$task]->recv(), 3); return $encode ? json_decode($res) : $res; } return null; }
$worker->send("READY"); return array($worker, $identity); } $context = new ZMQContext(); list($worker, $identity) = s_worker_socket($context); // If liveness hits zero, queue is considered disconnected $liveness = HEARTBEAT_LIVENESS; $interval = INTERVAL_INIT; // Send out heartbeats at regular intervals $heartbeat_at = microtime(true) + HEARTBEAT_INTERVAL; $read = $write = array(); $cycles = 0; while (true) { $poll = new ZMQPoll(); $poll->add($worker, ZMQ::POLL_IN); $events = $poll->poll($read, $write, HEARTBEAT_INTERVAL * 1000); if ($events) { // Get message // - 3-part envelope + content -> request // - 1-part "HEARTBEAT" -> heartbeat $zmsg = new Zmsg($worker); $zmsg->recv(); if ($zmsg->parts() == 3) { // Simulate various problems, after a few cycles $cycles++; if ($cycles > 3 && rand(0, 5) == 0) { printf("I: (%s) simulating a crash%s", $identity, PHP_EOL); break; } elseif ($cycles > 3 && rand(0, 5) == 0) { printf("I: (%s) simulating CPU overload%s", $identity, PHP_EOL); sleep(5);
/** * Returns the reply message or NULL if there was no reply. Does not * attempt to recover from a broker failure, this is not possible * without storing all unanswered requests and resending them all... * */ public function recv() { $read = $write = array(); // Poll socket for a reply, with timeout $poll = new ZMQPoll(); $poll->add($this->client, ZMQ::POLL_IN); $events = $poll->poll($read, $write, $this->timeout); // If we got a reply, process it if ($events) { $msg = new Zmsg($this->client); $msg->recv(); if ($this->verbose) { echo "I: received reply:", $msg->__toString(), PHP_EOL; } // Don't try to handle errors, just assert noisily assert($msg->parts() >= 4); $msg->pop(); // empty $header = $msg->pop(); assert($header == MDPC_CLIENT); $reply_service = $msg->pop(); return $msg; // Success } else { echo "W: permanent error, abandoning request", PHP_EOL; return; // Give up } }
/** * 等待应答 * * @param integer $timeout 请求超时时间(毫秒) * @param boolean $autofetch 是否自动获取结果 * @param boolean $keep 是否保留结果 * @return integer 未收到应答的请求数 */ public function wait_for_replies($timeout = -1, $autofetch = TRUE, $keep = FALSE) { //页面清除cache //是否开启页面清除cache $open_clear_page_cache = APF::get_instance()->get_config('open_clear_page_cache'); //要接受的getkey $clear_page_cache_key = APF::get_instance()->get_config('clear_page_cache_key'); //要接受的getval $clear_page_cache_val = APF::get_instance()->get_config('clear_page_cache_val'); if ($open_clear_page_cache) { //如果接受设定的get方法中有值不为空,则清空当前cache if (APF::get_instance()->get_request()) { $isclearcache = APF::get_instance()->get_request()->get_parameter($clear_page_cache_key); if ($isclearcache == $clear_page_cache_val) { apf_require_class('GlobalFunc'); //判断ip段 if (GlobalFunc::is_allow_debug()) { $timeout = -1; } } } } try { if (APS::get_instance()->get_zmq_enabled()) { $poll = new ZMQPoll(); // foreach (self::$sockets as $socket) { // $poll->add($socket, ZMQ::POLL_IN); // } $poll->add($this->socket, ZMQ::POLL_IN); $start = APS_Functions::aps_millitime(); $pending = count($this->requests); $readable = $writeable = array(); while ($pending > 0 && $timeout > 0) { $events = $poll->poll($readable, $writeable, $timeout); if ($events == 0) { break; } foreach ($readable as $socket) { $this->process_reply($socket); --$pending; } $millitime = APS_Functions::aps_millitime(); $timeout -= $millitime - $start; if ($timeout <= 0) { break; } $start = $millitime; } } if ($autofetch) { $this->fetch_all_replies($keep); $pending = 0; } } catch (Exception $e) { error_log(print_r('Caught exception: ' . $e->getMessage() . "\n", 1), 3, '/tmp/replaceWords.log'); } return $pending; }
public function multiple_pollerAction() { $context = new ZMQContext(); $receiver = new ZMQSocket($context, ZMQ::SOCKET_PULL); $receiver->connect("tcp://127.0.0.1:5557"); $subscriber = new ZMQSocket($context, ZMQ::SOCKET_SUB); $subscriber->connect("tcp://127.0.0.1:5556"); $subscriber->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, "10001"); //DebugTools::print_r($context); $poll = new ZMQPoll(); $poll->add($receiver, ZMQ::POLL_IN); $poll->add($subscriber, ZMQ::POLL_IN); $readable = $writeable = array(); while (true) { $events = $poll->poll($readable, $writeable); if ($events > 0) { foreach ($readable as $socket) { if ($socket === $receiver) { $message = $socket->recv(); } else { if ($socket === $subscriber) { $message = $socket->recv(); } } } } } }
return $client; } $context = new ZMQContext(); $client = client_socket($context); $sequence = 0; $retries_left = REQUEST_RETRIES; $read = $write = array(); while ($retries_left) { // We send a request, then we work to get a reply $client->send(++$sequence); $expect_reply = true; while ($expect_reply) { // Poll socket for a reply, with timeout $poll = new ZMQPoll(); $poll->add($client, ZMQ::POLL_IN); $events = $poll->poll($read, $write, REQUEST_TIMEOUT * 1000); // If we got a reply, process it if ($events > 0) { // We got a reply from the server, must match sequence $reply = $client->recv(); if (intval($reply) == $sequence) { printf("I: server replied OK (%s)%s", $reply, PHP_EOL); $retries_left = REQUEST_RETRIES; $expect_reply = false; } else { printf("E: malformed reply from server: %s%s", $reply, PHP_EOL); } } else { if (--$retries_left == 0) { echo "E: server seems to be offline, abandoning", PHP_EOL; break;
function main() { for ($client_nbr = 0; $client_nbr < NBR_CLIENTS; $client_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { client_thread(); return; } } for ($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { worker_thread(); return; } } $context = new ZMQContext(); $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $backend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $frontend->bind("ipc://frontend.ipc"); $backend->bind("ipc://backend.ipc"); // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers $available_workers = 0; $worker_queue = array(); $writeable = $readable = array(); while ($client_nbr > 0) { $poll = new ZMQPoll(); // Poll front-end only if we have available workers if ($available_workers > 0) { $poll->add($frontend, ZMQ::POLL_IN); } // Always poll for worker activity on backend $poll->add($backend, ZMQ::POLL_IN); $events = $poll->poll($readable, $writeable); if ($events > 0) { foreach ($readable as $socket) { // Handle worker activity on backend if ($socket === $backend) { // Queue worker address for LRU routing $zmsg = new Zmsg($socket); $zmsg->recv(); assert($available_workers < NBR_WORKERS); $available_workers++; array_push($worker_queue, $zmsg->unwrap()); if ($zmsg->body() != "READY") { $zmsg->set_socket($frontend)->send(); // exit after all messages relayed $client_nbr--; } } else { if ($socket === $frontend) { $zmsg = new Zmsg($socket); $zmsg->recv(); $zmsg->wrap(array_shift($worker_queue), ""); $zmsg->set_socket($backend)->send(); $available_workers--; } } } } } // Clean up our worker processes foreach ($worker_queue as $worker) { $zmsg = new Zmsg($backend); $zmsg->body_set('END')->wrap($worker, "")->send(); } sleep(1); }
/* Bind to port 5555 on 127.0.0.1 */ $server->bind("tcp://127.0.0.1:5555"); /* Create new pollset for incoming/outgoing message */ $poll = new ZMQPoll(); /* Add the object and listen for poll in/out */ $id = $poll->add($server, ZMQ::POLL_IN | ZMQ::POLL_OUT); echo "Added object with id " . $id . "\n"; /* Initialise readable and writable arrays */ $readable = array(); $writable = array(); while (true) { /* Amount of events retrieved */ $events = 0; try { /* Poll until there is something to do */ $events = $poll->poll($readable, $writable, -1); $errors = $poll->getLastErrors(); if (count($errors) > 0) { foreach ($errors as $error) { echo "Error polling object " . $error . "\n"; } } } catch (ZMQPollException $e) { echo "poll failed: " . $e->getMessage() . "\n"; } if ($events > 0) { /* Loop through readable objects and recv messages */ foreach ($readable as $r) { try { echo "Received message: " . $r->recv() . "\n"; } catch (ZMQException $e) {
/** * Must be started when already running as daemon. */ public function start() { $this->registerSignals(); // For SIGTERM handling $poll = new \ZMQPoll(); foreach ($this->connections as $connection) { $connection->connect(); $poll->add($connection->pull_socket, \ZMQ::POLL_IN); } // We are using polling to not block indefinitely and be able // to process the SIGTERM signal. The poll timeout is .5 second. $timeout = 500; $to_read = $to_write = array(); $gc = gc_enabled(); $i = 0; while (true) { $events = 0; try { $events = $poll->poll($to_read, $to_write, $timeout); $errors = $poll->getLastErrors(); if (count($errors) > 0) { foreach ($errors as $error) { Log::error('Error polling object: ' . $error); } } } catch (\ZMQPollException $e) { Log::fatal('Poll failed: ' . $e->getMessage()); return 1; } if ($events > 0) { foreach ($to_read as $r) { foreach ($this->connections as $connection) { if ($connection->pull_socket === $r) { $this->processRequest($connection); break; } } $i++; } } pcntl_signal_dispatch(); if ($gc && 500 < $i) { $collected = gc_collect_cycles(); Log::debug(array('photon.server.start', 'collected_cycles', $collected)); $i = 0; } } }
* @author Ian Barber <ian(dot)barber(at)gmail(dot)com> */ // Prepare our context and sockets $context = new ZMQContext(); $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $backend = new ZMQSocket($context, ZMQ::SOCKET_DEALER); $frontend->bind("tcp://*:5559"); $backend->bind("tcp://*:5560"); // Initialize poll set $poll = new ZMQPoll(); $poll->add($frontend, ZMQ::POLL_IN); $poll->add($backend, ZMQ::POLL_IN); $readable = $writeable = array(); // Switch messages between sockets while (true) { $events = $poll->poll($readable, $writeable); foreach ($readable as $socket) { if ($socket === $frontend) { // Process all parts of the message while (true) { $message = $socket->recv(); // Multipart detection $more = $socket->getSockOpt(ZMQ::SOCKOPT_RCVMORE); $backend->send($message, $more ? ZMQ::MODE_SNDMORE : null); if (!$more) { break; // Last message part } } } elseif ($socket === $backend) { $message = $socket->recv();
/** * Send request to broker and get reply by hook or crook * Takes ownership of request message and destroys it when sent. * Returns the reply message or NULL if there was no reply. * * @param string $service * @param Zmsg $request * @param string $client * @return Zmsg */ public function send($service, Zmsg $request) { // Prefix request with protocol frames // Frame 1: "MDPCxy" (six bytes, MDP/Client // Frame 2: Service name (printable string) $request->push($service); $request->push(MDPC_CLIENT); if ($this->verbose) { printf("I: send request to '%s' service:", $service); echo $request->__toString(); } $retries_left = $this->retries; $read = $write = array(); while ($retries_left) { $request->set_socket($this->client)->send(); // Poll socket for a reply, with timeout $poll = new ZMQPoll(); $poll->add($this->client, ZMQ::POLL_IN); $events = $poll->poll($read, $write, $this->timeout); // If we got a reply, process it if ($events) { $request->recv(); if ($this->verbose) { echo "I: received reply:", $request->__toString(), PHP_EOL; } // Don't try to handle errors, just assert noisily assert($request->parts() >= 3); $header = $request->pop(); assert($header == MDPC_CLIENT); $reply_service = $request->pop(); assert($reply_service == $service); return $request; // Success } elseif ($retries_left--) { if ($this->verbose) { echo "W: no reply, reconnecting...", PHP_EOL; } // Reconnect, and resend message $this->connect_to_broker(); $request->send(); } else { echo "W: permanent error, abandoning request", PHP_EOL; break; // Give up } } }