예제 #1
0
 /**
  * Constructor.
  *
  * @param AMQPMessage $message Message with serialized event.
  */
 public function __construct(AMQPMessage $message)
 {
     $this->message = $message;
     $body = Util::jsonDecode($message->body);
     $this->firedAt = Util::datetimeFromString($body->fired_at);
     $this->name = $body->name;
     $this->eventId = $body->event_id;
     $ref = new \ReflectionClass(EventName::payloadClassForName($body->name));
     $this->payload = $ref->getMethod('newFromResponse')->invoke(null, $body->payload);
 }
예제 #2
0
 /**
  * Constructor.
  * - translates 'under_score' names into 'camelCase'
  * - converts datetime fields value into \Datetime
  * 
  * @param \stdClass $object Raw object returned by Fatmouse
  */
 public function __construct($object)
 {
     foreach (get_object_vars($object) as $key => $value) {
         if (substr($key, -4) === 'date') {
             $value = new \Datetime($value);
         }
         $key = Util::camelize($key);
         $this->{$key} = $value;
     }
 }
예제 #3
0
 /**
  * Convert object into Fatmouse request data.
  *
  * - replace camelCase with under_score
  * - format Datetime values as ISO8601 string
  *
  * @return \stdClass Fatmouse request part.
  */
 public function toRequest()
 {
     $retval = new \stdClass();
     $ref = new \ReflectionObject($this);
     foreach ($ref->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
         $key = Util::underscorize($prop->getName());
         $value = $this->{$prop->getName()};
         if ($value instanceof self) {
             $value = $value->toRequest();
         } elseif ($value instanceof \DateTime) {
             $value = Util::datetimeToString($value);
         }
         $retval->{$key} = $value;
     }
     return $retval;
 }
예제 #4
0
 /**
  * Constucts object.
  *
  * @param callable             $callback   Callable to call for each consumed event.
  * @param AMQPStreamConnection $connection AMQP connection object.
  * @param string               $queue      Queue to bind.
  * @param string               $exchange   An events exchange.
  * @param string               $bindingKey A binding key.
  *
  * @throws ErrorException On network\transport errors.
  */
 public function __construct(callable $callback, AMQPStreamConnection $connection, $queue, $exchange, $bindingKey)
 {
     // TODO: consumer shoud has own connection with heartbeat.
     // The heartbeat is checked only during IO operations, so when AMQP connection
     // not used for a long time, RabbitMQ terminates connection
     $this->queue = $queue;
     $this->bindingKey = $bindingKey;
     $this->channel = $connection->channel();
     Util::declareQueue($connection, $queue, ['durable' => true, 'exclusive' => false]);
     Util::declareExchange($connection, $exchange, 'direct', ['auto_delete' => false]);
     $ch->queue_bind($queue, $exchange, $bindingKey);
     $wrapper = function ($msg) use($callback) {
         $event = new Event($msg);
         return $callback($event);
     };
     $ch->basic_consume($this->queue, '', false, false, false, false, $wrapper);
 }
예제 #5
0
 /**
  * Translate result message value into Task object.
  *
  * @return void
  * @throws Errors\ClientException When result message has not yet been received.
  */
 private function translate()
 {
     if ($this->task) {
         return;
     }
     if (!isset($this->message)) {
         throw Errors\ClientException('Result has not yet been received');
     }
     $celeryMsg = Util::jsonDecode($this->message->body);
     $this->task = Fatmouse::newTaskFromCeleryMessage($celeryMsg, $this->taskName);
 }
예제 #6
0
 /**
  * Generates Celery task-id and serializes task call into a message.
  *
  * @param string $taskName Celery task name.
  * @param array  $kwargs   Optional Celery task parameters.
  *
  * @return [taskId, messageBody] A pair of task-id and call message body.
  */
 private function prepareCeleryTask($taskName, array $kwargs = null)
 {
     $taskId = str_replace('-', '', self::newUUID4());
     // Celery replaces '-' in task id
     $task = ['id' => $taskId, 'task' => $taskName, 'args' => [], 'kwargs' => (object) $kwargs ?: new \stdClass()];
     return [$taskId, Util::jsonEncode($task)];
 }
예제 #7
0
 /**
  * Generic method to synchronously call Fatmouse Agent tasks.
  * 
  * Create result queue for the task and bind it to results exchange.
  * Scalr uses agent tasks directly in synchronous manner (mostly for
  * retrieving server stats), and due to very high request rate we need
  * to clean up per-task result queues ASAP.
  *
  * `auto-delete` argument makes sure that queue will be deleted after last queue
  * consumer disconnected. (Won't be deleted if there weren't any consumers)
  *
  * `x-expires` queue option means that queue will be deleted if it's unused for the
  * specified time in milliseconds. Unused means that queue has no consumers,
  * the queue has not been redeclared, and basic.get has not been invoked.
  * 
  * Example: Call Fatmouse Agent task
  * <code>
  * <?php
  * $serverId = "cf3a320b-7ac6-4b88-810a-c760a94e1875";
  * $taskName = "sys.set_hostname";
  * $params = ["hostname" => "myexample.com"];
  * $timeout = 5; 
  * $result = $fatmouse->callAgentSync($serverId, $taskName, $params, $timeout);
  * ?>
  * </code>
  * 
  * @param string $serverId Scalr server-id to call task at
  * @param string $taskName Agent task name
  * @param array $kwargs optional Task parameters
  * @param integer $timeout optional Result timeout in seconds
  * @return \stdClass|mixed Task result 
  */
 public function callAgentSync($serverId, $taskName, $kwargs = null, $timeout = null)
 {
     list($taskId, $serializedTask) = $this->prepareCeleryTask($taskName, $kwargs);
     $serverExchange = 'server.' . $serverId . '.celery';
     $connection = $this->getConnection();
     $channel = $connection->channel();
     $timeout = $timeout === null ? $this->defaultCallAgentTimeout : $timeout;
     try {
         Util::declareQueue($connection, $taskId, ['durable' => false, 'auto_delete' => true, 'arguments' => $timeout ? ['x-expires' => $timeout * 1000] : null]);
         Util::declareExchange($connection, 'celeryresults', 'direct');
         $channel->queue_bind($taskId, 'celeryresults', $taskId);
         // Sending task to server's queue
         $msg = new AMQPMessage($serializedTask, $this->publishParams);
         $channel->basic_publish($msg, $serverExchange);
         $result = null;
         $setResult = function ($msg) use(&$result) {
             $result = Util::jsonDecode($msg->body);
         };
         // Setting callback for message
         $channel->basic_consume($taskId, '', false, true, false, false, $setResult);
         try {
             $channel->wait(null, false, $timeout);
         } catch (AMQPTimeoutException $e) {
             throw new Errors\ClientException(sprintf("Timeout %d seconds exceeded while waiting for task '%s' to complete on server '%s'", $timeout, $taskName, $server_id));
         }
         return $result;
     } finally {
         $channel->close();
     }
 }