/** * Set the pre-fetch limits for consumers on this channel. * * @recoil-coroutine * * Only consumers created after setting the limits are affected. * * The pre-fetch count is the maximum number of unacknowledged messages that * are delivered to each consumer on this channel. * * The pre-fetch limit is the maximum total size of unacknowledge messages * (in bytes) that is delivered to this channel. * * This feature requires the "per_consumer_qos" broker capability. * * RabbitMQ does not support pre-fetch size limits (current as of v3.5.6). * * @param int|null $count The pre-fetch count limit (null = unlimited). * @param int|null $size The pre-fetch size limit (null = unlimited). * * @throws NotSupportedException The broker does not support this feature. * @throws ConnectionException The connection is closed. * @throws ChannelException The channel is closed. */ public function setConsumerQosLimits(int $count = null, int $size = null) : Generator { assert($size === null || $size > 0); assert($count === null || $count > 0); if ($this->channelManager === null) { throw ChannelException::notOpen($this->channelId); } elseif (!$this->features->perConsumerQos) { throw NotSupportedException::missingCapability('per-consumer QoS limits', 'per_consumer_qos'); } elseif ($size !== null && !$this->features->qosSizeLimits) { throw NotSupportedException::unsupportedFeature('pre-fetch size limits'); } $this->channelManager->setDirty(); (yield $this->channelManager->call(BasicQosFrame::create($size ?: 0, $count ?: 0, false), BasicQosOkFrame::METHOD_ID)); }
/** * Get the next available channel ID. * * @throws ChannelException No channels are available. */ private function findChannelId() : int { // first check in range [next, max] ... for ($channelId = $this->nextChannelId; $channelId <= $this->tune->channelMax; ++$channelId) { if (!isset($this->channels[$channelId])) { $this->nextChannelId = $channelId + 1; return $channelId; } } // then check in range [min, next) ... for ($channelId = 1; $channelId < $this->nextChannelId; ++$channelId) { if (!isset($this->channels[$channelId])) { $this->nextChannelId = $channelId + 1; return $channelId; } } throw ChannelException::noAvailableChannels(); }
/** * @recoil-coroutine */ public function onCloseByBroker(ChannelCloseFrame $frame) : Generator { $this->connectionManager->removeChannel($this->channelId); $exception = AmqpException::create($frame->replyText, $frame->replyCode); // The closure was triggered by a previously sent frame. Find the // offending strand and resume it with an exception specific to this // closure ... if ($frame->classId && $frame->methodId) { $sentMethod = $frame->classId << 16 | $frame->methodId; ($callers =& $this->callersBySentMethod[$sentMethod]) ?? null; if ($callers !== null) { foreach ($callers as $id => $waitMethod) { $strand = $this->callers[$waitMethod][$id]; unset($this->callers[$waitMethod][$id], $this->callersBySentMethod[$sentMethod][$id], $this->callersByWaitMethod[$waitMethod][$id]); (yield Recoil::throw($strand, $exception)); break; } } } // Acknowledge the closure ... $frame = new ChannelCloseOkFrame(); $frame->frameChannelId = $this->channelId; (yield $this->transport->write($frame)); // Procee to the regular on-close logic. To all remaining callers and // listeners this is an unexpected closure ... (yield $this->onClose(ChannelException::closedUnexpectedly($this->channelId, $exception))); }