예제 #1
9
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;
            }
        }
    }
}
예제 #2
0
파일: PollBroker.php 프로젝트: limitium/zmq
 /**
  * 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);
     }
 }
예제 #3
0
 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();
 }
예제 #4
0
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();
            }
        }
    }
}
예제 #5
0
 /**
  * @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;
 }
예제 #6
0
 /**
  * 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);
         }
     }
 }
예제 #7
0
파일: LogTest.php 프로젝트: limitium/zmq
 /**
  * @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.
 }
예제 #8
0
 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"));
 }
예제 #9
0
파일: Worker.php 프로젝트: sgraebner/tp
 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();
     }
 }
예제 #10
0
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();
                }
            }
        }
    }
}
예제 #11
0
 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');
 }
예제 #12
0
파일: Client.php 프로젝트: 0rpc/zerorpc-php
 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');
     }
 }
예제 #13
0
 /**
  * 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();
         }
     }
 }
예제 #15
0
/**
* @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);
            }
        }
    }
}
예제 #17
0
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);
}
예제 #18
0
 /**
  * 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;
         }
     }
 }
예제 #19
0
$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
예제 #20
0
파일: task.php 프로젝트: photon/photon
 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;
 }
예제 #21
0
    $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);
예제 #22
0
 /**
  * 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
     }
 }
예제 #23
0
 /**
  * 等待应答
  *
  * @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;
 }
예제 #24
0
 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();
                     }
                 }
             }
         }
     }
 }
예제 #25
0
    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;
예제 #26
0
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);
}
예제 #27
0
/* 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) {
예제 #28
0
파일: server.php 프로젝트: photon/photon
 /**
  * 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;
         }
     }
 }
예제 #29
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();
예제 #30
0
 /**
  * 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
         }
     }
 }