Пример #1
0
 protected function onPoll($events, $read, $write)
 {
     parent::onPoll($events, $read, $write);
     if ($events > 0) {
         foreach ($read as $socket) {
             //handle publisher
             if ($socket === $this->frontedSocket) {
                 $zmsg = new Zmsg($this->frontedSocket);
                 $zmsg->recv();
                 if ($this->verbose) {
                     echo "I: received message from publisher size: ";
                     echo strlen($zmsg->__toString()), PHP_EOL;
                 }
                 $zmsg->unwrap();
                 //time
                 if ($this->queueLimit > sizeof($this->queue)) {
                     array_unshift($this->queue, $zmsg->pop());
                 }
             }
         }
     }
 }
Пример #2
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 * ZMQ_POLL_MSEC);
         //  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;
         }
     }
 }
Пример #3
0
 /**
  * Start listen for messages in loop
  * @throws \Exception
  */
 public function listen()
 {
     if (!$this->listener) {
         throw new \Exception("Empty listener");
     }
     $this->isListen = true;
     while ($this->isListen) {
         $zmsg = new Zmsg($this->socket);
         $zmsg->recv();
         if ($this->verbose) {
             echo "I: received message from broker:", PHP_EOL;
             echo $zmsg->__toString(), PHP_EOL;
         }
         $time = $zmsg->unwrap();
         if (!$this->normalDelay) {
             $this->normalDelay = microtime(true) * 1000 - (double) $time;
         }
         $delayTime = microtime(true) * 1000 - (double) $time;
         if ($this->misser && $delayTime > $this->normalDelay + $this->maxAllowedDelay) {
             call_user_func($this->misser, $zmsg->pop(), $time, $delayTime);
         }
         call_user_func($this->listener, $zmsg->pop(), $time);
     }
 }
Пример #4
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;
         }
     }
 }
Пример #5
0
         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);
         }
         printf("I: (%s) normal reply - %s%s", $identity, $zmsg->body(), PHP_EOL);
         $zmsg->send();
         $liveness = HEARTBEAT_LIVENESS;
         sleep(1);
         // Do some heavy work
     } elseif ($zmsg->parts() == 1 && $zmsg->body() == 'HEARTBEAT') {
         $liveness = HEARTBEAT_LIVENESS;
     } else {
         printf("E: (%s) invalid message%s%s", $identity, PHP_EOL, $zmsg->__toString());
     }
     $interval = INTERVAL_INIT;
 } elseif (--$liveness == 0) {
     printf("W: (%s) heartbeat failure, can't reach queue%s", $identity, PHP_EOL);
     printf("W: (%s) reconnecting in %d msec...%s", $identity, $interval, PHP_EOL);
     usleep($interval * 1000);
     if ($interval < INTERVAL_MAX) {
         $interval *= 2;
     }
     list($worker, $identity) = s_worker_socket($context);
     $liveness = HEARTBEAT_LIVENESS;
 }
 //  Send heartbeat to queue if it's time
 if (microtime(true) > $heartbeat_at) {
     $heartbeat_at = microtime(true) + HEARTBEAT_INTERVAL;
Пример #6
0
 /**
  * Process message sent to us by a worker
  *
  * @param string $sender
  * @param Zmsg $msg
  */
 public function worker_process($sender, $msg)
 {
     $command = $msg->pop();
     $worker_ready = isset($this->workers[$sender]);
     $worker = $this->worker_require($sender);
     if ($command == MDPW_READY) {
         if ($worker_ready) {
             $this->worker_delete($worker, true);
             //  Not first command in session
         } else {
             if (strlen($sender) >= 4 && substr($sender, 0, 4) == 'mmi.') {
                 $this->worker_delete($worker, true);
             } else {
                 //  Attach worker to service and mark as idle
                 $service_frame = $msg->pop();
                 $worker->service = $this->service_require($service_frame);
                 $worker->service->workers++;
                 $this->worker_waiting($worker);
             }
         }
     } else {
         if ($command == MDPW_REPLY) {
             if ($worker_ready) {
                 //  Remove & save client return envelope and insert the
                 //  protocol header and service name, then rewrap envelope.
                 $client = $msg->unwrap();
                 $msg->push($worker->service->name);
                 $msg->push(MDPC_CLIENT);
                 $msg->wrap($client, "");
                 $msg->set_socket($this->socket)->send();
                 $this->worker_waiting($worker);
             } else {
                 $this->worker_delete($worker, true);
             }
         } else {
             if ($command == MDPW_HEARTBEAT) {
                 if ($worker_ready) {
                     $worker->expiry = microtime(true) + HEARTBEAT_EXPIRY / 1000;
                 } else {
                     $this->worker_delete($worker, true);
                 }
             } else {
                 if ($command == MDPW_DISCONNECT) {
                     $this->worker_delete($worker, true);
                 } else {
                     echo "E: invalid input message", PHP_EOL, $msg->__toString();
                 }
             }
         }
     }
 }
Пример #7
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
     }
 }
Пример #8
0
 protected function process($sender, Zmsg $zmsg)
 {
     $command = $zmsg->pop();
     $hasWorker = $this->hasWorker($sender);
     switch ($command) {
         case Commands::W_READY:
             if (!$hasWorker) {
                 $this->addWorker($sender);
             } else {
                 echo "E: Ready from ready worker `{$sender}` - disconnect ", PHP_EOL;
                 $this->deleteWorker($this->workers[$sender], true);
             }
             break;
         case Commands::W_HEARTBEAT:
             if ($hasWorker) {
                 $this->live($this->workers[$sender]);
             } else {
                 echo "E: Heartbeat from not ready worker `{$sender}` - disconnect ", PHP_EOL;
                 $this->send($sender, Commands::W_RESPONSE);
             }
             break;
         case Commands::W_RESPONSE:
             if ($hasWorker) {
                 if ($this->responder) {
                     $response = $zmsg->pop();
                     call_user_func($this->responder, $response);
                 }
                 $this->free($this->workers[$sender]);
             } else {
                 echo "E: Response from not ready worker `{$sender}` - disconnect ", PHP_EOL;
                 $this->send($sender, Commands::W_RESPONSE);
             }
             break;
         default:
             echo "E: Unsupported command `{$command}`.", PHP_EOL;
             echo $zmsg->__toString(), PHP_EOL, PHP_EOL;
     }
 }
Пример #9
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
         }
     }
 }
Пример #10
0
 foreach ($read as $socket) {
     $zmsg = new Zmsg($socket);
     $zmsg->recv();
     //  Handle worker activity on backend
     if ($socket === $backend) {
         $identity = $zmsg->unwrap();
         //  Return reply to client if it's not a control message
         if ($zmsg->parts() == 1) {
             if ($zmsg->address() == "READY") {
                 $queue->s_worker_delete($identity);
                 $queue->s_worker_append($identity);
             } else {
                 if ($zmsg->address() == 'HEARTBEAT') {
                     $queue->s_worker_refresh($identity);
                 } else {
                     printf("E: invalid message from %s%s%s", $identity, PHP_EOL, $zmsg->__toString());
                 }
             }
         } else {
             $zmsg->set_socket($frontend)->send();
             $queue->s_worker_append($identity);
         }
     } else {
         //  Now get next client request, route to next worker
         $identity = $queue->s_worker_dequeue();
         $zmsg->wrap($identity);
         $zmsg->set_socket($backend)->send();
     }
 }
 if (microtime(true) > $heartbeat_at) {
     foreach ($queue as $id => $expiry) {
Пример #11
0
 /**
  * Send request to broker
  * Takes ownership of request message and destroys it when sent.
  *
  * @param string $service 
  * @param Zmsg $request 
  */
 public function send($service, Zmsg $request)
 {
     //  Prefix request with protocol frames
     //  Frame 0: empty (REQ emulation)
     //  Frame 1: "MDPCxy" (six bytes, MDP/Client x.y)
     //  Frame 2: Service name (printable string)
     $request->push($service);
     $request->push(MDPC_CLIENT);
     $request->push("");
     if ($this->verbose) {
         printf("I: send request to '%s' service: %s", $service, PHP_EOL);
         echo $request->__toString();
     }
     $request->set_socket($this->client)->send();
 }
Пример #12
0
 protected function onPoll($events, $read, $write)
 {
     $events = $this->poll->poll($read, $write, $this->heartbeatDelay);
     $sendHeartBeat = true;
     if ($events) {
         $zmsg = new Zmsg($this->socket);
         $zmsg->recv();
         if ($this->verbose) {
             echo "I: received message from broker:", PHP_EOL;
             echo $zmsg->__toString(), PHP_EOL;
         }
         $this->heartbeatTriesLeft = $this->heartbeatMaxFails;
         $zmsg->pop();
         $header = $zmsg->pop();
         assert($header == Commands::W_WORKER);
         $command = $zmsg->pop();
         if ($command == Commands::W_HEARTBEAT) {
         } elseif ($command == Commands::W_REQUEST) {
             //@todo: get address
             $result = call_user_func($this->executor, $zmsg->pop());
             $this->send($result);
             //resp = HB
             $sendHeartBeat = false;
         } elseif ($command == Commands::W_RESPONSE) {
             $this->connect();
         } else {
             echo "I: Unsupported command `{$command}`.", PHP_EOL;
             echo $zmsg->__toString(), PHP_EOL, PHP_EOL;
         }
     } elseif (--$this->heartbeatTriesLeft == 0) {
         if ($this->verbose) {
             echo "I: disconnected from broker - retrying... ", PHP_EOL;
         }
         usleep($this->reconnectDelay * 1000);
         $this->connect();
     }
     $this->sendHeartbeat($sendHeartBeat);
 }