/** * Determine how to deliver the message. This depends on what's in the interface configuration, delivery section. * If a callback is supplied, that is executed. * @param <type> $msg * @param <type> $conf * @TODO: would be easy to generalise onerror into a list of these actions that are * done in sequence. e.g. log an error and then requeue it. * @TODO: would be good to have a failure count on the error message. Not sure how to * represent this generally. */ static function deliver_message($msgframe, $conf) { if (!$conf || !isset($conf["delivery"])) { throw new Exception("deliver_message failed because it was not passed valid configuration with delivery section"); } $del = $conf["delivery"]; try { if (isset($del["requeue"])) { // delivery means stick it in another queue. This is expected to be an array with at least a queue name if (!is_array($del["requeue"])) { throw new Exception("delivery of message failed because it specifies requeue, but it is not the expected array"); } $newQueue = isset($del["requeue"]["queue"]) ? $del["requeue"]["queue"] : null; if (!$newQueue) { throw new Exception("delivery of message failed because it specified requeue, but doesn't specify a queue"); } $newConf = MessageQueue::get_queue_config($newQueue); if (isset($del["requeue"]["immediate"]) && $del["requeue"]["immediate"]) { // Immediate execution - get the configuration for the queue, and recurse to deliver immediately. MessageQueue::deliver_message($msgframe, $newConf); } else { // Not immediate, so put this message on the specified queue, and it will hopefully get delivered at // some later time. MessageQueue::send($newConf, $msgframe); } } else { if (isset($del["callback"])) { // delivery is via a callback call_user_func_array($del["callback"], array($msgframe, $conf)); } else { if (is_object($msgframe->body) && $msgframe->body instanceof MessageExecutable) { $msgframe->body->execute($msgframe, $conf); } else { throw new Exception("delivery of message failed because there is no specification of what to do with it"); } } } } catch (Exception $e) { // Look at the config to determine what to do with a failed message. $onerror = isset($del["onerror"]) ? $del["onerror"] : "drop"; if (!is_array($onerror)) { $list = array($onerror); } else { $list = $onerror; } // There are two types of entry. Those with numeric keys have the action // as the value. Those with non-numeric keys have the key as the action, // and the value as an argument. foreach ($list as $key => $value) { if (is_numeric($key)) { $action = $value; $arg = null; } else { $action = $key; $arg = $value; } switch ($action) { case "drop": break; // do nothing // do nothing case "requeue": if (!$arg) { $arg = $msgframe->queue; } // requeue on the same queue if not specified. MessageQueue::send($arg, $msgframe->body, $msgframe->header); break; case "log": SS_Log::log($e, null); echo $e->getMessage(); break; case "callback": if (!$arg) { throw new Exception("delivery of message failed with error callback indicated, but no callback function supplied"); } call_user_func_array($arg, array($e, $msgframe)); break; default: throw new Exception("Invalid onerror action '{$action}'"); } } } }
/** * Given a message received by a remote system, unencode the message and deliver it. * @param $queue * @param $message * @return void */ function processRawMessage($raw) { $cooked = $this->decode($raw); $queue = $cooked["queue"]; $msgframe = $cooked["msgframe"]; $conf = MessageQueue::get_queue_config($queue); MessageQueue::decode_message($msgframe, $conf); MessageQueue::deliver_message($msgframe, $conf); }