Ejemplo n.º 1
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();
            }
        }
    }
}
Ejemplo n.º 2
0
 private function sendCommand($command, $msg = null)
 {
     if (!$msg) {
         $msg = new Zmsg();
     }
     $msg->push($command);
     $msg->push(Commands::W_WORKER);
     $msg->push("");
     if ($this->verbose) {
         printf("I: sending `%s` to broker %s", $command, PHP_EOL);
         echo $msg->__toString(), PHP_EOL;
     }
     $msg->set_socket($this->socket)->send();
 }
Ejemplo n.º 3
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();
 }
Ejemplo n.º 4
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();
                }
            }
        }
    }
}
Ejemplo n.º 5
0
 //  - Route any request locally if we can, else to cloud
 while ($local_capacity + $cloud_capacity) {
     $poll = new ZMQPoll();
     $poll->add($localfe, ZMQ::POLL_IN);
     if ($local_capacity) {
         $poll->add($cloudfe, ZMQ::POLL_IN);
     }
     $reroutable = false;
     $events = $poll->poll($readable, $writeable, 0);
     if ($events > 0) {
         foreach ($readable as $socket) {
             $zmsg = new Zmsg($socket);
             $zmsg->recv();
             if ($local_capacity) {
                 $zmsg->wrap(array_shift($worker_queue), "");
                 $zmsg->set_socket($localbe)->send();
                 $local_capacity--;
             } else {
                 //  Route to random broker peer
                 printf("I: route request %s to cloud...%s", $zmsg->body(), PHP_EOL);
                 $zmsg->wrap($_SERVER['argv'][mt_rand(2, $_SERVER['argc'] - 1)]);
                 $zmsg->set_socket($cloudbe)->send();
             }
         }
     } else {
         break;
         //  No work, go back to backends
     }
 }
 if ($local_capacity != $previous) {
     //  Broadcast new capacity
Ejemplo n.º 6
0
    $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
            //  REQ socket in worker needs an envelope delimiter
            //  Dequeue and drop the next worker address
            $zmsg->wrap(array_shift($worker_queue), "");
            $zmsg->set_socket($backend)->send();
            $available_workers--;
        }
    }
    //  We never exit the main loop
}
Ejemplo n.º 7
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();
                 }
             }
         }
     }
 }
Ejemplo n.º 8
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);
}
Ejemplo n.º 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
         }
     }
 }
Ejemplo n.º 10
0
 /**
  * Initialise the master server that dispatches job to the worker processes
  *
  * @param int $port
  */
 protected function initAsMaster($port)
 {
     $ctx = new ZMQContext();
     $client = $ctx->getSocket(ZMQ::SOCKET_XREP);
     $client->bind('tcp://*:' . $port);
     $workers = $ctx->getSocket(ZMQ::SOCKET_XREQ);
     $workers->bind('ipc://' . $this->workersIpcName);
     $this->log(__CLASS__, "Master listening on port {$port}");
     $readable = $writable = array();
     while (true) {
         $poll = new ZMQPoll();
         $poll->add($client, ZMQ::POLL_IN);
         $poll->add($workers, ZMQ::POLL_IN);
         $poll->poll($readable, $writable);
         foreach ($readable as $socket) {
             $zmsg = new Zmsg($socket);
             $zmsg->recv();
             if ($socket === $client) {
                 $this->log(__CLASS__, "Master sending job to worker");
                 $zmsg->set_socket($workers)->send();
             } else {
                 if ($socket === $workers) {
                     $this->log(__CLASS__, "Master sending reply to client");
                     $zmsg->set_socket($client)->send();
                 }
             }
         }
     }
 }