public function testComplex() { $context = new \ZMQContext(); $output = new \ZMQSocket($context, \ZMQ::SOCKET_DEALER); $output->bind("inproc://zmsg_selftest"); $input = new \ZMQSocket($context, \ZMQ::SOCKET_ROUTER); $input->connect("inproc://zmsg_selftest"); // Test send and receive of single-part message $zmsgo = new Zmsg($output); $zmsgo->setLast("Hello"); $this->assertTrue($zmsgo->getLast() == "Hello"); $zmsgo->send(); $zmsgi = new Zmsg($input); $zmsgi->recv(); $this->assertTrue($zmsgi->parts() == 2); $this->assertTrue($zmsgi->getLast() == "Hello"); // Test send and receive of multi-part message $zmsgo = new Zmsg($output); $zmsgo->setLast("Hello"); $zmsgo->wrap("address1", ""); $zmsgo->wrap("address2"); $this->assertTrue($zmsgo->parts() == 4); $zmsgo->send(); $zmsgi = new Zmsg($input); $zmsgi->recv(); $this->assertTrue($zmsgi->parts() == 5); $zmsgi->unwrap(); $this->assertTrue($zmsgi->unwrap() == "address2"); $zmsgi->setLast(sprintf("%s%s", 'W', "orld")); $this->assertTrue($zmsgi->getLast() == "World"); // Pull off address 1, check that empty part was dropped $zmsgi->unwrap(); $this->assertTrue($zmsgi->parts() == 1); // Check that message body was correctly modified $part = $zmsgi->pop(); $this->assertTrue($part == "World"); $this->assertTrue($zmsgi->parts() == 0); // Test load and save $zmsg = new Zmsg(); $zmsg->setLast("Hello"); $zmsg->wrap("address1", ""); $zmsg->wrap("address2"); $this->assertTrue($zmsg->parts() == 4); $fh = fopen(sys_get_temp_dir() . "/zmsgtest.zmsg", 'w'); $zmsg->save($fh); fclose($fh); $fh = fopen(sys_get_temp_dir() . "/zmsgtest.zmsg", 'r'); $zmsg2 = new Zmsg(); $zmsg2->load($fh); assert($zmsg2->getLast() == $zmsg->getLast()); fclose($fh); $this->assertTrue($zmsg2->parts() == 4); }
try { $strRequestPayload = @json_encode($payload->body); $payload->setBody($task->worker($payload->body)); $payload->code = 200; } catch (Exception $e) { $task->log('ERROR', "Worker %s failed with exception:%s - %s", $task->getName(), get_class($e), $e->getMessage()); $payload = $payload->error(500, $e->getMessage()); } $executionTime = microtime(true) - $start; $statPath = '/var/log/scalr/worker.log'; if (is_writable($statPath)) { @error_log(sprintf("%s,%d,\"%s\",%0.4f,%d,\"%s\"\n", date('M d H:i:s P'), isset($payload->code) ? $payload->code : 500, $service, $executionTime, \Scalr::getDb()->numberQueries + (\Scalr::getContainer()->analytics->enabled ? \Scalr::getContainer()->cadb->numberQueries : 0), str_replace('"', '""', $strRequestPayload)), 3, $statPath); } //Resets the number of the queries \Scalr::getDb()->numberQueries = 0; if (\Scalr::getContainer()->analytics->enabled) { \Scalr::getContainer()->cadb->numberQueries = 0; } } //It checks memory usage for demonized tasks if ($config->daemon && !$task->checkMemoryUsage()) { //Adds the pid of the process to payload to handle it on client's side $payload->dw = posix_getpid(); //It does not even exit execution loop. Client should start a replacement in its time. //We cannot start worker from here because it won't be correctly terminated by client. } $reply = new Zmsg(); $reply->setLast(serialize($payload)); unset($payload); unset($request); }
/** * Handle internal service according to 8/MMI specification * * @param string $frame The frame * @param \Scalr\System\Zmq\Zmsg $msg The message */ protected function handleInternalService($frame, $msg) { if ($frame == "mmi.service") { $name = $msg->getLast(); $service = isset($this->services[$name]) ? $this->services[$name] : null; $code = !empty($service->workers) ? "200" : "404"; } else { $code = "501"; } $client = $msg->unwrap(); $msg->setLast($code); //NOTE! We changed a bit ZMQ MDP protocol here. //The number of registered workers for the service follows the status frame. $msg->append(sprintf("%s", isset($service->workers) ? intval($service->workers) : "0")); $msg->push($frame); $msg->push(Mdp::CLIENT); $msg->wrap($client, ""); if ($this->verbose) { $this->log("ZMQDEBUG", "responding mmi.service:\n--\n%s", (string) $msg); } $msg->setSocket($this->socket)->send(); }
/** * Runs ZMQ MDP Asynchronous Client * * @throws Exception */ protected function launchClient() { $this->launchWorkers(); //We don't even need to start client if queue is empty if ($this->queue->count() == 0) { $this->log('DEBUG', "It does not need to start major-domo client as queue is empty."); return; } $this->log('DEBUG', "Launching %s 0mq mdp client", $this->name); $session = (new AsynClient(\Scalr::config('scalr.crontab.sockets.broker'), true))->setLogger(\Scalr::getContainer()->logger('Mdp\\AsynClient')->setLevel(\Scalr::config('scalr.crontab.log_level')))->setTimeout(\Scalr::config('scalr.crontab.heartbeat.delay') * \Scalr::config('scalr.crontab.heartbeat.liveness') * 2)->connect(); $this->log('DEBUG', 'Sending request messages to broker'); $payloadClass = $this->payloadClass; //The number of the requests sent $count = 0; //Array of the messages which are sent $sentMessages = []; //Gets queue iterator in order to gracefully iterate over an ArrayObject removing each offset $it = $this->queue->getIterator(); //Sending messages loop while ($it->valid()) { $key = $it->key(); //Creates standard payload for zmq messaging $payload = (new $payloadClass($it->current()))->setId(); $sentMessages[$payload->getId()] = $payload; $request = new Zmsg(); $request->setLast(serialize($payload)); //Sends the message to worker if ($payload instanceof PayloadRouterInterface) { $session->send($payload->getAddress($this), $request); } else { $session->send($this->name, $request); } $count++; $it->next(); //Removing the message from the queue $it->offsetUnset($key); } //Cleanup queue unset($this->queue); $this->log('DEBUG', 'Polling results'); //Receiving loop for ($i = 0; $i < $count; $i++) { $msg = $session->recv(); if (!$msg) { // Interrupt or failure $this->getLogger()->fatal("Some worker failed!"); break; } //We are having deal with serialized data $payload = @unserialize($msg->getLast()); if (!$payload instanceof AbstractPayload) { throw new TaskException(sprintf("Unexpected reply from worker: '%s'.", $msg->getLast())); } //Checks if worker reaches a memory limit if (!empty($payload->dw)) { $this->toDisconnect[$payload->dw] = $payload instanceof PayloadRouterInterface ? $payload->getAddress($this) : $this->name; $this->log("DEBUG", "Client got PID:%d from the worker %s to disconnect", $payload->dw, $this->toDisconnect[$payload->dw]); } if (!isset($sentMessages[$payload->getId()])) { //Message comes from previous session? $this->getLogger()->warn("Strange message came from another session. Payload:%s", var_export($payload, true)); $count++; } else { //We get response so remove record unset($sentMessages[$payload->getId()]); //Triggers onResponse callback $this->onResponse($payload); } } if (!empty($this->toDisconnect) && $this->config()->daemon) { foreach ($this->toDisconnect as $pid => $address) { //Terminates worker $this->terminateWorker($pid); //We need to get up a replacement for that one $pid = $this->addWorker($address); //It is important to save a PID of the process to be able terminate all workers along with client $this->pids[$pid] = $pid; } //Resets event $this->toDisconnect = []; usleep(100000); } $this->onCompleted(); }