diff --git a/.gitignore b/.gitignore index 867741b9e6b2755d3c64fe45bd6514726a6f5618..73e172cf7095e2e4f5f721c1586379570d42d703 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,7 @@ var/ # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec - +resources/amqp0-9-1.xml # Installer logs pip-log.txt pip-delete-this-directory.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 44aef32aa9488159054df560a6eecaf23257ea6a..be2ea144546b609e4f0c8e3325a0d4e3c3a5690e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,3 +4,4 @@ have been made so far, between releases. # v1.2.17 +* can support building from XML not containing Connection.Blocked and Connection.Unblocked diff --git a/README.md b/README.md index 26827f8a02273f3ca6570ae7f003b0703e5bc8a0..0ec57f9a1eb19697e29433b7e079950aa4b99de3 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,14 @@ CoolAMQP [](http://coolamqp.readthedocs.io/en/latest/?badge=develop) []() -A **magical** AMQP 0.9.1 client, that uses **heavy sorcery** to achieve speeds that other pure-Python AMQP clients cannot even hope to match. -Additionally, it's traceable using **opentracing**. +Why CoolAMQP? +------------- + +* AMQP 0.9.1 client that's native Python +* heavily optimized for speed +* geared towards interfacing with [RabbitMQ](https://www.rabbitmq.com/ + * supports custom RabbitMQ commands and Connection.Blocked and Connection.Unblocked +* traceable using [opentracing](https://opentracing.io/) Documentation (WIP) is available at [Read the Docs](http://coolamqp.readthedocs.io/). @@ -89,6 +95,11 @@ In order to compile the definitions: ```python python -m compile_definitions ``` +* you can alternatively perform + ```python + python -m compile_definitions --no-connection-blocked + ``` + To generate a variant not supporting Connection.Blocked and Connection.Unblocked commands and you're all set. The only files modified is [definitions.py](coolamqp/framing/definitions.py). diff --git a/compile_definitions/__main__.py b/compile_definitions/__main__.py index 970b17e740e66388300d412a1b7052f0ae6b9a1d..0df419359f11a292794c9652597e462827a325a7 100644 --- a/compile_definitions/__main__.py +++ b/compile_definitions/__main__.py @@ -1,10 +1,18 @@ from __future__ import division +import os +import sys +if sys.version.startswith('2.'): + raise RuntimeError('Cannot run under Python 2.7') + +from urllib.request import urlopen import collections import math import struct import subprocess +from io import BytesIO from xml.etree import ElementTree +from zipfile import ZipFile import six @@ -26,11 +34,26 @@ TYPE_TRANSLATOR = { } -def compile_definitions(xml_file='resources/amqp0-9-1.extended.xml', +def get_xml(xml_file): + """Download XML definition from OASIS's website""" + + r = urlopen('https://raw.githubusercontent.com/postwait/node-amqp/master/amqp-0-9-1-rabbit.xml') + with open(xml_file, 'wb') as out: + out.write(r.read()) + + +def compile_definitions(xml_file='resources/amqp0-9-1.xml', out_file='coolamqp/framing/definitions.py'): """parse resources/amqp-0-9-1.xml into """ + if not os.path.exists(xml_file): + get_xml(xml_file) + + try: + xml = ElementTree.parse(xml_file) + except ElementTree.ParseError: + get_xml(xml_file) + xml = ElementTree.parse(xml_file) - xml = ElementTree.parse(xml_file) out = open(out_file, 'wb') out.write(u'''# coding=UTF-8 @@ -568,7 +591,12 @@ REPLIES_FOR = {\n''') if __name__ == '__main__': - compile_definitions() + if '--no-connection-blocked' in sys.argv: + xml_file = 'resources/amqp0-9-1.xml' + print('Compiling without Connection.Blocked') + else: + xml_file = 'resources/amqp0-9-1.extended.xml' + compile_definitions(xml_file=xml_file) proc = subprocess.check_output(['yapf', 'coolamqp/framing/definitions.py']) with open('coolamqp/framing/definitions.py', 'wb') as f_out: f_out.write(proc) diff --git a/coolamqp/attaches/publisher.py b/coolamqp/attaches/publisher.py index a93b5d9bae4a5620de2e62e46c3acacbdb2cbcba..39661dc7d444bd6ed81a163608a673000a4ce902 100644 --- a/coolamqp/attaches/publisher.py +++ b/coolamqp/attaches/publisher.py @@ -24,10 +24,15 @@ from coolamqp.framing.frames import AMQPMethodFrame, AMQPBodyFrame, \ try: # these extensions will be available from coolamqp.framing.definitions import ConfirmSelect, ConfirmSelectOk, \ - BasicNack, ChannelFlow, ChannelFlowOk, ConnectionBlocked, ConnectionUnblocked + BasicNack, ChannelFlow, ChannelFlowOk except ImportError: pass +try: + from coolamqp.framing.definitions import ConnectionUnblocked, ConnectionBlocked +except ImportError: + ConnectionBlocked, ConnectionUnblocked = None, None + from coolamqp.attaches.channeler import Channeler, ST_ONLINE, ST_OFFLINE from coolamqp.uplink import PUBLISHER_CONFIRMS, MethodWatch, FailWatch from coolamqp.attaches.utils import AtomicTagger, FutureConfirmableRejectable, \ @@ -108,9 +113,9 @@ class Publisher(Channeler, Synchronized): connection.watch(FailWatch(self.on_fail)) def on_connection_blocked(self, payload): - if isinstance(payload, ConnectionBlocked): + if ConnectionBlocked is not None and isinstance(payload, ConnectionBlocked): self.blocked = True - elif isinstance(payload, ConnectionUnblocked): + elif ConnectionUnblocked is not None and isinstance(payload, ConnectionUnblocked): self.blocked = False if self.content_flow: @@ -321,9 +326,10 @@ class Publisher(Channeler, Synchronized): mw = self.watch_for_method(ChannelFlow, self.on_flow_control) mw.oneshot = False - mw = self.connection.watch_for_method(0, (ConnectionBlocked, ConnectionUnblocked), - self.on_connection_blocked) - mw.oneshot = False + if ConnectionBlocked is not None: + mw = self.connection.watch_for_method(0, (ConnectionBlocked, ConnectionUnblocked), + self.on_connection_blocked) + mw.oneshot = False if self.mode == Publisher.MODE_CNPUB: self.method_and_watch(ConfirmSelect(False), ConfirmSelectOk, diff --git a/coolamqp/clustering/single.py b/coolamqp/clustering/single.py index 8d3b883213744c27d4c5839b8b9727d9483a75ff..d799e04bcb9d2b245d89df04df48f423b8fdcbeb 100644 --- a/coolamqp/clustering/single.py +++ b/coolamqp/clustering/single.py @@ -4,7 +4,11 @@ from __future__ import print_function, absolute_import, division import logging import typing as tp -from coolamqp.framing.definitions import ConnectionUnblocked, ConnectionBlocked +try: + from coolamqp.framing.definitions import ConnectionUnblocked, ConnectionBlocked +except ImportError: + ConnectionBlocked, ConnectionUnblocked = None, None + from coolamqp.objects import Callable from coolamqp.uplink import Connection from coolamqp.uplink.connection import MethodWatch @@ -57,13 +61,15 @@ class SingleNodeReconnector(object): self.connection.finalize.add(self.on_fail) # Register the on-blocking watches - mw = MethodWatch(0, (ConnectionBlocked,), lambda: self.on_blocked(True)) - mw.oneshot = False - self.connection.watch(mw) - - mw = MethodWatch(0, (ConnectionUnblocked,), lambda: self.on_blocked(False)) - mw.oneshot = False - self.connection.watch(mw) + if ConnectionBlocked is not None: + mw = MethodWatch(0, (ConnectionBlocked,), lambda: self.on_blocked(True)) + mw.oneshot = False + self.connection.watch(mw) + + if ConnectionUnblocked is not None: + mw = MethodWatch(0, (ConnectionUnblocked,), lambda: self.on_blocked(False)) + mw.oneshot = False + self.connection.watch(mw) def _on_fail(self): if self.terminating: diff --git a/coolamqp/tracing.py b/coolamqp/tracing.py index 0f7fa628ddafa6586a6549d49b5ca77a9ca7374a..e293a409eb910ec5a2bfa0f8af64a8d183a4480e 100644 --- a/coolamqp/tracing.py +++ b/coolamqp/tracing.py @@ -23,11 +23,11 @@ class LoggingFrameTracer(BaseFrameTracer): """ A frame tracer that outputs each frame to log - :param logger: the logger to log onto + :param logger: the logger to log onto (defaults to logging.getLogger(__name__)) :param log_level: the level of logging to log with """ - def __init__(self, logger, log_level=logging.WARNING): - self.logger = logger + def __init__(self, logger=None, log_level=logging.WARNING): + self.logger = logger or logging.getLogger(__name__) self.log_level = log_level def on_frame(self, timestamp, frame, direction): diff --git a/docs/cluster.rst b/docs/cluster.rst new file mode 100644 index 0000000000000000000000000000000000000000..2fd0d83d71d5484376879775c8b97c203b1844c7 --- /dev/null +++ b/docs/cluster.rst @@ -0,0 +1,24 @@ +CoolAMQP cluster +================ + +.. autoclass:: coolamqp.clustering.Cluster + :members: + + +Publisher +--------- + +.. autoclass:: coolamqp.attaches.publisher.Publisher + :members: + :undoc-members: + +Consumers +--------- + +.. autoclass:: coolamqp.attaches.consumer.BodyReceiveMode + :members: + +.. autoclass:: coolamqp.attaches.consumer.Consumer + :members: + :undoc-members: + diff --git a/docs/coolamqp/cluster.rst b/docs/coolamqp/cluster.rst deleted file mode 100644 index 73af6b09b9c335a3b4950ad54337ec1234f97e83..0000000000000000000000000000000000000000 --- a/docs/coolamqp/cluster.rst +++ /dev/null @@ -1,5 +0,0 @@ -CoolAMQP cluster -================ - -.. autoclass:: coolamqp.clustering.Cluster - :members: diff --git a/docs/index.rst b/docs/index.rst index 58ee4eaba45073cdcef6ea7973249522e75b1bcf..69444a6ea8b8a66394155f44800aba0b8628ea3d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,7 +5,7 @@ Welcome to CoolAMQP's documentation! :maxdepth: 2 :caption: Contents - coolamqp/cluster + cluster tutorial caveats frames diff --git a/resources/amqp0-9-1.xml b/resources/amqp0-9-1.xml deleted file mode 100644 index 2d56a5eb8d7aa5e3846f62929c8668430ecef71e..0000000000000000000000000000000000000000 --- a/resources/amqp0-9-1.xml +++ /dev/null @@ -1,3474 +0,0 @@ -<?xml version = "1.0"?> -<!-- - Copyright Notice - ================ - Copyright (c) 2006-2008 Cisco Systems, Credit Suisse, Deutsche Boerse - Systems, Envoy Technologies, Inc., Goldman Sachs, IONA Technologies PLC, - iMatix Corporation, JPMorgan Chase Bank Inc. N.A, Novell, Rabbit - Technologies Ltd., Red Hat, Inc., TWIST Process Innovations Ltd, WS02 - Inc. and 29West Inc. All rights reserved. - - License - ======= - Cisco Systems, Credit Suisse, Deutsche Boerse Systems, Envoy Technologies, - Inc., Goldman Sachs, IONA Technologies PLC, iMatix Corporation, JPMorgan - Chase Bank Inc. N.A, Novell, Rabbit Technologies Ltd., Red Hat, Inc., - TWIST Process Innovations Ltd, WS02, Inc. and 29West Inc. (collectively, - the "Authors") each hereby grants to you a worldwide, perpetual, - royalty-free, nontransferable, nonexclusive license to (i) copy, display, - distribute and implement the Advanced Messaging Queue Protocol ("AMQP") - Specification and (ii) the Licensed Claims that are held by the Authors, - all for the purpose of implementing the Advanced Messaging Queue Protocol - Specification. Your license and any rights under this Agreement will - terminate immediately without notice from any Author if you bring any - claim, suit, demand, or action related to the Advanced Messaging Queue - Protocol Specification against any Author. Upon termination, you shall - destroy all copies of the Advanced Messaging Queue Protocol Specification - in your possession or control. - - As used hereunder, "Licensed Claims" means those claims of a patent or - patent application, throughout the world, excluding design patents and - design registrations, owned or controlled, or that can be sublicensed - without fee and in compliance with the requirements of this Agreement, - by an Author or its affiliates now or at any future time and which would - necessarily be infringed by implementation of the Advanced Messaging - Queue Protocol Specification. A claim is necessarily infringed hereunder - only when it is not possible to avoid infringing it because there is no - plausible non-infringing alternative for implementing the required - portions of the Advanced Messaging Queue Protocol Specification. - Notwithstanding the foregoing, Licensed Claims shall not include any - claims other than as set forth above even if contained in the same patent - as Licensed Claims; or that read solely on any implementations of any - portion of the Advanced Messaging Queue Protocol Specification that are - not required by the Advanced Messaging Queue ProtocolSpecification, or - that, if licensed, would require a payment of royalties by the licensor - to unaffiliated third parties. Moreover, Licensed Claims shall not - include (i) any enabling technologies that may be necessary to make or - use any Licensed Product but are not themselves expressly set forth in - the Advanced Messaging Queue Protocol Specification (e.g., semiconductor - manufacturing technology, compiler technology, object oriented - technology, networking technology, operating system technology, and the - like); or (ii) the implementation of other published standards developed - elsewhere and merely referred to in the body of the Advanced Messaging - Queue Protocol Specification, or (iii) any Licensed Product and any - combinations thereof the purpose or function of which is not required - for compliance with the Advanced Messaging Queue Protocol Specification. - For purposes of this definition, the Advanced Messaging Queue Protocol - Specification shall be deemed to include both architectural and - interconnection requirements essential for interoperability and may also - include supporting source code artifacts where such architectural, - interconnection requirements and source code artifacts are expressly - identified as being required or documentation to achieve compliance with - the Advanced Messaging Queue Protocol Specification. - - As used hereunder, "Licensed Products" means only those specific portions - of products (hardware, software or combinations thereof) that implement - and are compliant with all relevant portions of the Advanced Messaging - Queue Protocol Specification. - - The following disclaimers, which you hereby also acknowledge as to any - use you may make of the Advanced Messaging Queue Protocol Specification: - - THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS," - AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE - CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE - SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED - MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY - PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. - - THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, - INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY - USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE - PROTOCOL SPECIFICATION. - - The name and trademarks of the Authors may NOT be used in any manner, - including advertising or publicity pertaining to the Advanced Messaging - Queue Protocol Specification or its contents without specific, written - prior permission. Title to copyright in the Advanced Messaging Queue - Protocol Specification will at all times remain with the Authors. - - No other rights are granted by implication, estoppel or otherwise. - - Upon termination of your license or rights under this Agreement, you - shall destroy all copies of the Advanced Messaging Queue Protocol - Specification in your possession or control. - - Trademarks - ========== - JPMorgan, JPMorgan Chase, Chase, the JPMorgan Chase logo and the - Octagon Symbol are trademarks of JPMorgan Chase & Co. - - IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl. - - IONA, IONA Technologies, and the IONA logos are trademarks of IONA - Technologies PLC and/or its subsidiaries. - - LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered - trademarks of Red Hat, Inc. in the US and other countries. - - Java, all Java-based trademarks and OpenOffice.org are trademarks of - Sun Microsystems, Inc. in the United States, other countries, or both. - - Other company, product, or service names may be trademarks or service - marks of others. - - Links to full AMQP specification: - ================================= - http://www.amqp.org ---> - -<!-- - <!DOCTYPE amqp SYSTEM "amqp.dtd"> ---> - -<!-- XML Notes - - We use entities to indicate repetition; attributes to indicate properties. - - We use the 'name' attribute as an identifier, usually within the context - of the surrounding entities. - - We use spaces to seperate words in names, so that we can print names in - their natural form depending on the context - underlines for source code, - hyphens for written text, etc. - - We do not enforce any particular validation mechanism but we support all - mechanisms. The protocol definition conforms to a formal grammar that is - published seperately in several technologies. - - --> - -<amqp major="0" minor="9" revision="1" - port="5672" comment="AMQ Protocol version 0-9-1"> - <!-- - ====================================================== - == CONSTANTS - ====================================================== - --> - <!-- Frame types --> - <constant name="frame-method" value="1"/> - <constant name="frame-header" value="2"/> - <constant name="frame-body" value="3"/> - <constant name="frame-heartbeat" value="8"/> - - <!-- Protocol constants --> - <constant name="frame-min-size" value="4096"/> - <constant name="frame-end" value="206"/> - - <!-- Reply codes --> - <constant name="reply-success" value="200"> - <doc> - Indicates that the method completed successfully. This reply code is - reserved for future use - the current protocol design does not use - positive - confirmation and reply codes are sent only in case of an error. - </doc> - </constant> - - <constant name="content-too-large" value="311" class="soft-error"> - <doc> - The client attempted to transfer content larger than the server - could accept - at the present time. The client may retry at a later time. - </doc> - </constant> - - <constant name="no-consumers" value="313" class="soft-error"> - <doc> - When the exchange cannot deliver to a consumer when the immediate - flag is - set. As a result of pending data on the queue or the absence of any - consumers of the queue. - </doc> - </constant> - - <constant name="connection-forced" value="320" class="hard-error"> - <doc> - An operator intervened to close the connection for some reason. The - client - may retry at some later date. - </doc> - </constant> - - <constant name="invalid-path" value="402" class="hard-error"> - <doc> - The client tried to work with an unknown virtual host. - </doc> - </constant> - - <constant name="access-refused" value="403" class="soft-error"> - <doc> - The client attempted to work with a server entity to which it has no - access due to security settings. - </doc> - </constant> - - <constant name="not-found" value="404" class="soft-error"> - <doc> - The client attempted to work with a server entity that does not - exist. - </doc> - </constant> - - <constant name="resource-locked" value="405" class="soft-error"> - <doc> - The client attempted to work with a server entity to which it has no - access because another client is working with it. - </doc> - </constant> - - <constant name="precondition-failed" value="406" class="soft-error"> - <doc> - The client requested a method that was not allowed because some - precondition - failed. - </doc> - </constant> - - <constant name="frame-error" value="501" class="hard-error"> - <doc> - The sender sent a malformed frame that the recipient could not - decode. - This strongly implies a programming error in the sending peer. - </doc> - </constant> - - <constant name="syntax-error" value="502" class="hard-error"> - <doc> - The sender sent a frame that contained illegal values for one or - more - fields. This strongly implies a programming error in the sending - peer. - </doc> - </constant> - - <constant name="command-invalid" value="503" class="hard-error"> - <doc> - The client sent an invalid sequence of frames, attempting to perform - an - operation that was considered invalid by the server. This usually - implies - a programming error in the client. - </doc> - </constant> - - <constant name="channel-error" value="504" class="hard-error"> - <doc> - The client attempted to work with a channel that had not been - correctly - opened. This most likely indicates a fault in the client layer. - </doc> - </constant> - - <constant name="unexpected-frame" value="505" class="hard-error"> - <doc> - The peer sent a frame that was not expected, usually in the context - of - a content header and body. This strongly indicates a fault in the - peer's - content processing. - </doc> - </constant> - - <constant name="resource-error" value="506" class="hard-error"> - <doc> - The server could not complete the method because it lacked - sufficient - resources. This may be due to the client creating too many of some - type - of entity. - </doc> - </constant> - - <constant name="not-allowed" value="530" class="hard-error"> - <doc> - The client tried to work with some entity in a manner that is - prohibited - by the server, due to security settings or by some other criteria. - </doc> - </constant> - - <constant name="not-implemented" value="540" class="hard-error"> - <doc> - The client tried to use functionality that is not implemented in the - server. - </doc> - </constant> - - <constant name="internal-error" value="541" class="hard-error"> - <doc> - The server could not complete the method because of an internal - error. - The server may require intervention by an operator in order to - resume - normal operations. - </doc> - </constant> - - <!-- - ====================================================== - == DOMAIN TYPES - ====================================================== - --> - - <domain name="class-id" type="short"/> - - <domain name="consumer-tag" type="shortstr" label="consumer tag"> - <doc> - Identifier for the consumer, valid within the current channel. - </doc> - </domain> - - <domain name="delivery-tag" type="longlong" - label="server-assigned delivery tag"> - <doc> - The server-assigned and channel-specific delivery tag - </doc> - <rule name="channel-local"> - <doc> - The delivery tag is valid only within the channel from which the - message was - received. I.e. a client MUST NOT receive a message on one - channel and then - acknowledge it on another. - </doc> - </rule> - <rule name="non-zero"> - <doc> - The server MUST NOT use a zero value for delivery tags. Zero is - reserved - for client use, meaning "all messages so far received". - </doc> - </rule> - </domain> - - <domain name="exchange-name" type="shortstr" label="exchange name"> - <doc> - The exchange name is a client-selected string that identifies the - exchange for - publish methods. - </doc> - <assert check="length" value="127"/> - <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> - </domain> - - <domain name="method-id" type="short"/> - - <domain name="no-ack" type="bit" label="no acknowledgement needed"> - <doc> - If this field is set the server does not expect acknowledgements for - messages. That is, when a message is delivered to the client the - server - assumes the delivery will succeed and immediately dequeues it. This - functionality may increase performance but at the cost of - reliability. - Messages can get lost if a client dies before they are delivered to - the - application. - </doc> - </domain> - - <domain name="no-local" type="bit" label="do not deliver own messages"> - <doc> - If the no-local field is set the server will not send messages to - the connection that - published them. - </doc> - </domain> - - <domain name="no-wait" type="bit" label="do not send reply method"> - <doc> - If set, the server will not respond to the method. The client should - not wait - for a reply method. If the server could not complete the method it - will raise a - channel or connection exception. - </doc> - </domain> - - <domain name="path" type="shortstr"> - <doc> - Unconstrained. - </doc> - <assert check="notnull"/> - <assert check="length" value="127"/> - </domain> - - <domain name="peer-properties" type="table"> - <doc> - This table provides a set of peer properties, used for - identification, debugging, - and general information. - </doc> - </domain> - - <domain name="queue-name" type="shortstr" label="queue name"> - <doc> - The queue name identifies the queue within the vhost. In methods - where the queue - name may be blank, and that has no specific significance, this - refers to the - 'current' queue for the channel, meaning the last queue that the - client declared - on the channel. If the client did not declare a queue, and the - method needs a - queue name, this will result in a 502 (syntax error) channel - exception. - </doc> - <assert check="length" value="127"/> - <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> - </domain> - - <domain name="redelivered" type="bit" label="message is being redelivered"> - <doc> - This indicates that the message has been previously delivered to - this or - another client. - </doc> - <rule name="implementation"> - <doc> - The server SHOULD try to signal redelivered messages when it - can. When - redelivering a message that was not successfully acknowledged, - the server - SHOULD deliver it to the original client if possible. - </doc> - <doc type="scenario"> - Declare a shared queue and publish a message to the queue. - Consume the - message using explicit acknowledgements, but do not acknowledge - the - message. Close the connection, reconnect, and consume from the - queue - again. The message should arrive with the redelivered flag set. - </doc> - </rule> - <rule name="hinting"> - <doc> - The client MUST NOT rely on the redelivered field but should - take it as a - hint that the message may already have been processed. A fully - robust - client must be able to track duplicate received messages on - non-transacted, - and locally-transacted channels. - </doc> - </rule> - </domain> - - <domain name="message-count" type="long" - label="number of messages in queue"> - <doc> - The number of messages in the queue, which will be zero for - newly-declared - queues. This is the number of messages present in the queue, and - committed - if the channel on which they were published is transacted, that are - not - waiting acknowledgement. - </doc> - </domain> - - <domain name="reply-code" type="short" label="reply code from server"> - <doc> - The reply code. The AMQ reply codes are defined as constants at the - start - of this formal specification. - </doc> - <assert check="notnull"/> - </domain> - - <domain name="reply-text" type="shortstr" label="localised reply text"> - <doc> - The localised reply text. This text can be logged as an aid to - resolving - issues. - </doc> - <assert check="notnull"/> - </domain> - - <!-- Elementary domains --> - <domain name="bit" type="bit" label="single bit"/> - <domain name="octet" type="octet" label="single octet"/> - <domain name="short" type="short" label="16-bit integer"/> - <domain name="long" type="long" label="32-bit integer"/> - <domain name="longlong" type="longlong" label="64-bit integer"/> - <domain name="shortstr" type="shortstr" label="short string"/> - <domain name="longstr" type="longstr" label="long string"/> - <domain name="timestamp" type="timestamp" label="64-bit timestamp"/> - <domain name="table" type="table" label="field table"/> - - <!-- == CONNECTION ======================================================= --> - - <class name="connection" handler="connection" index="10" - label="work with socket connections"> - <doc> - The connection class provides methods for a client to establish a - network connection to - a server, and for both peers to operate the connection thereafter. - </doc> - - <doc type="grammar"> - connection = open-connection *use-connection close-connection - open-connection = C:protocol-header - S:START C:START-OK - *challenge - S:TUNE C:TUNE-OK - C:OPEN S:OPEN-OK - challenge = S:SECURE C:SECURE-OK - use-connection = *channel - close-connection = C:CLOSE S:CLOSE-OK - / S:CLOSE C:CLOSE-OK - </doc> - - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MUST"/> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="start" synchronous="1" index="10" - label="start connection negotiation"> - <doc> - This method starts the connection negotiation process by telling - the client the - protocol version that the server proposes, along with a list of - security mechanisms - which the client can use for authentication. - </doc> - - <rule name="protocol-name"> - <doc> - If the server cannot support the protocol specified in the - protocol header, - it MUST respond with a valid protocol header and then close - the socket - connection. - </doc> - <doc type="scenario"> - The client sends a protocol header containing an invalid - protocol name. - The server MUST respond by sending a valid protocol header - and then closing - the connection. - </doc> - </rule> - <rule name="server-support"> - <doc> - The server MUST provide a protocol version that is lower - than or equal to - that requested by the client in the protocol header. - </doc> - <doc type="scenario"> - The client requests a protocol version that is higher than - any valid - implementation, e.g. 2.0. The server must respond with a - protocol header - indicating its supported protocol version, e.g. 1.0. - </doc> - </rule> - <rule name="client-support"> - <doc> - If the client cannot handle the protocol version suggested - by the server - it MUST close the socket connection without sending any - further data. - </doc> - <doc type="scenario"> - The server sends a protocol version that is lower than any - valid - implementation, e.g. 0.1. The client must respond by closing - the - connection without sending any further data. - </doc> - </rule> - - <chassis name="client" implement="MUST"/> - <response name="start-ok"/> - - <field name="version-major" domain="octet" - label="protocol major version"> - <doc> - The major version number can take any value from 0 to 99 as - defined in the - AMQP specification. - </doc> - </field> - - <field name="version-minor" domain="octet" - label="protocol minor version"> - <doc> - The minor version number can take any value from 0 to 99 as - defined in the - AMQP specification. - </doc> - </field> - - <field name="server-properties" domain="peer-properties" - label="server properties"> - <rule name="required-fields"> - <doc> - The properties SHOULD contain at least these fields: - "host", specifying the - server host name or address, "product", giving the name - of the server product, - "version", giving the name of the server version, - "platform", giving the name - of the operating system, "copyright", if appropriate, - and "information", giving - other general information. - </doc> - <doc type="scenario"> - Client connects to server and inspects the server - properties. It checks for - the presence of the required fields. - </doc> - </rule> - </field> - - <field name="mechanisms" domain="longstr" - label="available security mechanisms"> - <doc> - A list of the security mechanisms that the server supports, - delimited by spaces. - </doc> - <assert check="notnull"/> - </field> - - <field name="locales" domain="longstr" - label="available message locales"> - <doc> - A list of the message locales that the server supports, - delimited by spaces. The - locale defines the language in which the server will send - reply texts. - </doc> - <rule name="required-support"> - <doc> - The server MUST support at least the en_US locale. - </doc> - <doc type="scenario"> - Client connects to server and inspects the locales - field. It checks for - the presence of the required locale(s). - </doc> - </rule> - <assert check="notnull"/> - </field> - </method> - - <method name="start-ok" synchronous="1" index="11" - label="select security mechanism and locale"> - <doc> - This method selects a SASL security mechanism. - </doc> - - <chassis name="server" implement="MUST"/> - - <field name="client-properties" domain="peer-properties" - label="client properties"> - <rule name="required-fields"> - <!-- This rule is not testable from the client side --> - <doc> - The properties SHOULD contain at least these fields: - "product", giving the name - of the client product, "version", giving the name of the - client version, "platform", - giving the name of the operating system, "copyright", if - appropriate, and - "information", giving other general information. - </doc> - </rule> - </field> - - <field name="mechanism" domain="shortstr" - label="selected security mechanism"> - <doc> - A single security mechanisms selected by the client, which - must be one of those - specified by the server. - </doc> - <rule name="security"> - <doc> - The client SHOULD authenticate using the highest-level - security profile it - can handle from the list provided by the server. - </doc> - </rule> - <rule name="validity"> - <doc> - If the mechanism field does not contain one of the - security mechanisms - proposed by the server in the Start method, the server - MUST close the - connection without sending any further data. - </doc> - <doc type="scenario"> - Client connects to server and sends an invalid security - mechanism. The - server must respond by closing the connection (a socket - close, with no - connection close negotiation). - </doc> - </rule> - <assert check="notnull"/> - </field> - - <field name="response" domain="longstr" - label="security response data"> - <doc> - A block of opaque data passed to the security mechanism. The - contents of this - data are defined by the SASL security mechanism. - </doc> - <assert check="notnull"/> - </field> - - <field name="locale" domain="shortstr" - label="selected message locale"> - <doc> - A single message locale selected by the client, which must - be one of those - specified by the server. - </doc> - <assert check="notnull"/> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="secure" synchronous="1" index="20" - label="security mechanism challenge"> - <doc> - The SASL protocol works by exchanging challenges and responses - until both peers have - received sufficient information to authenticate each other. This - method challenges - the client to provide more information. - </doc> - - <chassis name="client" implement="MUST"/> - <response name="secure-ok"/> - - <field name="challenge" domain="longstr" - label="security challenge data"> - <doc> - Challenge information, a block of opaque binary data passed - to the security - mechanism. - </doc> - </field> - </method> - - <method name="secure-ok" synchronous="1" index="21" - label="security mechanism response"> - <doc> - This method attempts to authenticate, passing a block of SASL - data for the security - mechanism at the server side. - </doc> - - <chassis name="server" implement="MUST"/> - - <field name="response" domain="longstr" - label="security response data"> - <doc> - A block of opaque data passed to the security mechanism. The - contents of this - data are defined by the SASL security mechanism. - </doc> - <assert check="notnull"/> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="tune" synchronous="1" index="30" - label="propose connection tuning parameters"> - <doc> - This method proposes a set of connection configuration values to - the client. The - client can accept and/or adjust these. - </doc> - - <chassis name="client" implement="MUST"/> - - <response name="tune-ok"/> - - <field name="channel-max" domain="short" - label="proposed maximum channels"> - <doc> - Specifies highest channel number that the server permits. - Usable channel numbers - are in the range 1..channel-max. Zero indicates no specified - limit. - </doc> - </field> - - <field name="frame-max" domain="long" - label="proposed maximum frame size"> - <doc> - The largest frame size that the server proposes for the - connection, including - frame header and end-byte. The client can negotiate a lower - value. Zero means - that the server does not impose any specific limit but may - reject very large - frames if it cannot allocate resources for them. - </doc> - <rule name="minimum"> - <doc> - Until the frame-max has been negotiated, both peers MUST - accept frames of up - to frame-min-size octets large, and the minimum - negotiated value for frame-max - is also frame-min-size. - </doc> - <doc type="scenario"> - Client connects to server and sends a large properties - field, creating a frame - of frame-min-size octets. The server must accept this - frame. - </doc> - </rule> - </field> - - <field name="heartbeat" domain="short" - label="desired heartbeat delay"> - <doc> - The delay, in seconds, of the connection heartbeat that the - server wants. - Zero means the server does not want a heartbeat. - </doc> - </field> - </method> - - <method name="tune-ok" synchronous="1" index="31" - label="negotiate connection tuning parameters"> - <doc> - This method sends the client's connection tuning parameters to - the server. - Certain fields are negotiated, others provide capability - information. - </doc> - - <chassis name="server" implement="MUST"/> - - <field name="channel-max" domain="short" - label="negotiated maximum channels"> - <doc> - The maximum total number of channels that the client will - use per connection. - </doc> - <rule name="upper-limit"> - <doc> - If the client specifies a channel max that is higher - than the value provided - by the server, the server MUST close the connection - without attempting a - negotiated close. The server may report the error in - some fashion to assist - implementors. - </doc> - </rule> - <assert check="notnull"/> - <assert check="le" method="tune" field="channel-max"/> - </field> - - <field name="frame-max" domain="long" - label="negotiated maximum frame size"> - <doc> - The largest frame size that the client and server will use - for the connection. - Zero means that the client does not impose any specific - limit but may reject - very large frames if it cannot allocate resources for them. - Note that the - frame-max limit applies principally to content frames, where - large contents can - be broken into frames of arbitrary size. - </doc> - <rule name="minimum"> - <doc> - Until the frame-max has been negotiated, both peers MUST - accept frames of up - to frame-min-size octets large, and the minimum - negotiated value for frame-max - is also frame-min-size. - </doc> - </rule> - <rule name="upper-limit"> - <doc> - If the client specifies a frame max that is higher than - the value provided - by the server, the server MUST close the connection - without attempting a - negotiated close. The server may report the error in - some fashion to assist - implementors. - </doc> - </rule> - </field> - - <field name="heartbeat" domain="short" - label="desired heartbeat delay"> - <doc> - The delay, in seconds, of the connection heartbeat that the - client wants. Zero - means the client does not want a heartbeat. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="open" synchronous="1" index="40" - label="open connection to virtual host"> - <doc> - This method opens a connection to a virtual host, which is a - collection of - resources, and acts to separate multiple application domains - within a server. - The server may apply arbitrary limits per virtual host, such as - the number - of each type of entity that may be used, per connection and/or - in total. - </doc> - - <chassis name="server" implement="MUST"/> - <response name="open-ok"/> - - <field name="virtual-host" domain="path" label="virtual host name"> - <doc> - The name of the virtual host to work with. - </doc> - <rule name="separation"> - <doc> - If the server supports multiple virtual hosts, it MUST - enforce a full - separation of exchanges, queues, and all associated - entities per virtual - host. An application, connected to a specific virtual - host, MUST NOT be able - to access resources of another virtual host. - </doc> - </rule> - <rule name="security"> - <doc> - The server SHOULD verify that the client has permission - to access the - specified virtual host. - </doc> - </rule> - </field> - <!-- Deprecated: "capabilities", must be zero --> - <field name="reserved-1" type="shortstr" reserved="1"/> - <!-- Deprecated: "insist", must be zero --> - <field name="reserved-2" type="bit" reserved="1"/> - </method> - - <method name="open-ok" synchronous="1" index="41" - label="signal that connection is ready"> - <doc> - This method signals to the client that the connection is ready - for use. - </doc> - <chassis name="client" implement="MUST"/> - <!-- Deprecated: "known-hosts", must be zero --> - <field name="reserved-1" type="shortstr" reserved="1"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="close" synchronous="1" index="50" - label="request a connection close"> - <doc> - This method indicates that the sender wants to close the - connection. This may be - due to internal conditions (e.g. a forced shut-down) or due to - an error handling - a specific method, i.e. an exception. When a close is due to an - exception, the - sender provides the class and method id of the method which - caused the exception. - </doc> - <rule name="stability"> - <doc> - After sending this method, any received methods except Close - and Close-OK MUST - be discarded. The response to receiving a Close after - sending Close must be to - send Close-Ok. - </doc> - </rule> - - <chassis name="client" implement="MUST"/> - <chassis name="server" implement="MUST"/> - <response name="close-ok"/> - - <field name="reply-code" domain="reply-code"/> - <field name="reply-text" domain="reply-text"/> - - <field name="class-id" domain="class-id" - label="failing method class"> - <doc> - When the close is provoked by a method exception, this is - the class of the - method. - </doc> - </field> - - <field name="method-id" domain="method-id" - label="failing method ID"> - <doc> - When the close is provoked by a method exception, this is - the ID of the method. - </doc> - </field> - </method> - - <method name="close-ok" synchronous="1" index="51" - label="confirm a connection close"> - <doc> - This method confirms a Connection.Close method and tells the - recipient that it is - safe to release resources for the connection and close the - socket. - </doc> - <rule name="reporting"> - <doc> - A peer that detects a socket closure without having received - a Close-Ok - handshake method SHOULD log the error. - </doc> - </rule> - <chassis name="client" implement="MUST"/> - <chassis name="server" implement="MUST"/> - </method> - </class> - - <!-- == CHANNEL ========================================================== --> - - <class name="channel" handler="channel" index="20" - label="work with channels"> - <doc> - The channel class provides methods for a client to establish a - channel to a - server and for both peers to operate the channel thereafter. - </doc> - - <doc type="grammar"> - channel = open-channel *use-channel close-channel - open-channel = C:OPEN S:OPEN-OK - use-channel = C:FLOW S:FLOW-OK - / S:FLOW C:FLOW-OK - / functional-class - close-channel = C:CLOSE S:CLOSE-OK - / S:CLOSE C:CLOSE-OK - </doc> - - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MUST"/> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="open" synchronous="1" index="10" - label="open a channel for use"> - <doc> - This method opens a channel to the server. - </doc> - <rule name="state" on-failure="channel-error"> - <doc> - The client MUST NOT use this method on an already-opened - channel. - </doc> - <doc type="scenario"> - Client opens a channel and then reopens the same channel. - </doc> - </rule> - <chassis name="server" implement="MUST"/> - <response name="open-ok"/> - <!-- Deprecated: "out-of-band", must be zero --> - <field name="reserved-1" type="shortstr" reserved="1"/> - </method> - - <method name="open-ok" synchronous="1" index="11" - label="signal that the channel is ready"> - <doc> - This method signals to the client that the channel is ready for - use. - </doc> - <chassis name="client" implement="MUST"/> - <!-- Deprecated: "channel-id", must be zero --> - <field name="reserved-1" type="longstr" reserved="1"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="flow" synchronous="1" index="20" - label="enable/disable flow from peer"> - <doc> - This method asks the peer to pause or restart the flow of - content data sent by - a consumer. This is a simple flow-control mechanism that a peer - can use to avoid - overflowing its queues or otherwise finding itself receiving - more messages than - it can process. Note that this method is not intended for window - control. It does - not affect contents returned by Basic.Get-Ok methods. - </doc> - - <rule name="initial-state"> - <doc> - When a new channel is opened, it is active (flow is active). - Some applications - assume that channels are inactive until started. To emulate - this behaviour a - client MAY open the channel, then pause it. - </doc> - </rule> - - <rule name="bidirectional"> - <doc> - When sending content frames, a peer SHOULD monitor the - channel for incoming - methods and respond to a Channel.Flow as rapidly as - possible. - </doc> - </rule> - - <rule name="throttling"> - <doc> - A peer MAY use the Channel.Flow method to throttle incoming - content data for - internal reasons, for example, when exchanging data over a - slower connection. - </doc> - </rule> - - <rule name="expected-behaviour"> - <doc> - The peer that requests a Channel.Flow method MAY disconnect - and/or ban a peer - that does not respect the request. This is to prevent - badly-behaved clients - from overwhelming a server. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MUST"/> - - <response name="flow-ok"/> - - <field name="active" domain="bit" label="start/stop content frames"> - <doc> - If 1, the peer starts sending content frames. If 0, the peer - stops sending - content frames. - </doc> - </field> - </method> - - <method name="flow-ok" index="21" label="confirm a flow method"> - <doc> - Confirms to the peer that a flow command was received and - processed. - </doc> - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MUST"/> - <field name="active" domain="bit" label="current flow setting"> - <doc> - Confirms the setting of the processed flow method: 1 means - the peer will start - sending or continue to send content frames; 0 means it will - not. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="close" synchronous="1" index="40" - label="request a channel close"> - <doc> - This method indicates that the sender wants to close the - channel. This may be due to - internal conditions (e.g. a forced shut-down) or due to an error - handling a specific - method, i.e. an exception. When a close is due to an exception, - the sender provides - the class and method id of the method which caused the - exception. - </doc> - <rule name="stability"> - <doc> - After sending this method, any received methods except Close - and Close-OK MUST - be discarded. The response to receiving a Close after - sending Close must be to - send Close-Ok. - </doc> - </rule> - - <chassis name="client" implement="MUST"/> - <chassis name="server" implement="MUST"/> - <response name="close-ok"/> - - <field name="reply-code" domain="reply-code"/> - <field name="reply-text" domain="reply-text"/> - - <field name="class-id" domain="class-id" - label="failing method class"> - <doc> - When the close is provoked by a method exception, this is - the class of the - method. - </doc> - </field> - - <field name="method-id" domain="method-id" - label="failing method ID"> - <doc> - When the close is provoked by a method exception, this is - the ID of the method. - </doc> - </field> - </method> - - <method name="close-ok" synchronous="1" index="41" - label="confirm a channel close"> - <doc> - This method confirms a Channel.Close method and tells the - recipient that it is safe - to release resources for the channel. - </doc> - <rule name="reporting"> - <doc> - A peer that detects a socket closure without having received - a Channel.Close-Ok - handshake method SHOULD log the error. - </doc> - </rule> - <chassis name="client" implement="MUST"/> - <chassis name="server" implement="MUST"/> - </method> - </class> - - <!-- == EXCHANGE ========================================================= --> - - <class name="exchange" handler="channel" index="40" - label="work with exchanges"> - <doc> - Exchanges match and distribute messages across queues. Exchanges can - be configured in - the server or declared at runtime. - </doc> - - <doc type="grammar"> - exchange = C:DECLARE S:DECLARE-OK - / C:DELETE S:DELETE-OK - </doc> - - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MUST"/> - - <rule name="required-types"> - <doc> - The server MUST implement these standard exchange types: fanout, - direct. - </doc> - <doc type="scenario"> - Client attempts to declare an exchange with each of these - standard types. - </doc> - </rule> - <rule name="recommended-types"> - <doc> - The server SHOULD implement these standard exchange types: - topic, headers. - </doc> - <doc type="scenario"> - Client attempts to declare an exchange with each of these - standard types. - </doc> - </rule> - <rule name="required-instances"> - <doc> - The server MUST, in each virtual host, pre-declare an exchange - instance - for each standard exchange type that it implements, where the - name of the - exchange instance, if defined, is "amq." followed by the - exchange type name. - </doc> - <doc> - The server MUST, in each virtual host, pre-declare at least two - direct - exchange instances: one named "amq.direct", the other with no - public name - that serves as a default exchange for Publish methods. - </doc> - <doc type="scenario"> - Client declares a temporary queue and attempts to bind to each - required - exchange instance ("amq.fanout", "amq.direct", "amq.topic", and - "amq.headers" - if those types are defined). - </doc> - </rule> - <rule name="default-exchange"> - <doc> - The server MUST pre-declare a direct exchange with no public - name to act as - the default exchange for content Publish methods and for default - queue bindings. - </doc> - <doc type="scenario"> - Client checks that the default exchange is active by specifying - a queue - binding with no exchange name, and publishing a message with a - suitable - routing key but without specifying the exchange name, then - ensuring that - the message arrives in the queue correctly. - </doc> - </rule> - <rule name="default-access"> - <doc> - The server MUST NOT allow clients to access the default exchange - except - by specifying an empty exchange name in the Queue.Bind and - content Publish - methods. - </doc> - </rule> - <rule name="extensions"> - <doc> - The server MAY implement other exchange types as wanted. - </doc> - </rule> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="declare" synchronous="1" index="10" - label="verify exchange exists, create if needed"> - <doc> - This method creates an exchange if it does not already exist, - and if the exchange - exists, verifies that it is of the correct and expected class. - </doc> - <rule name="minimum"> - <doc> - The server SHOULD support a minimum of 16 exchanges per - virtual host and - ideally, impose no limit except as defined by available - resources. - </doc> - <doc type="scenario"> - The client declares as many exchanges as it can until the - server reports - an error; the number of exchanges successfully declared must - be at least - sixteen. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - <response name="declare-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="exchange" domain="exchange-name"> - <rule name="reserved" on-failure="access-refused"> - <doc> - Exchange names starting with "amq." are reserved for - pre-declared and - standardised exchanges. The client MAY declare an - exchange starting with - "amq." if the passive option is set, or the exchange - already exists. - </doc> - <doc type="scenario"> - The client attempts to declare a non-existing exchange - starting with - "amq." and with the passive option set to zero. - </doc> - </rule> - <rule name="syntax" on-failure="precondition-failed"> - <doc> - The exchange name consists of a non-empty sequence of - these characters: - letters, digits, hyphen, underscore, period, or colon. - </doc> - <doc type="scenario"> - The client attempts to declare an exchange with an - illegal name. - </doc> - </rule> - <assert check="notnull"/> - </field> - - <field name="type" domain="shortstr" label="exchange type"> - <doc> - Each exchange belongs to one of a set of exchange types - implemented by the - server. The exchange types define the functionality of the - exchange - i.e. how - messages are routed through it. It is not valid or - meaningful to attempt to - change the type of an existing exchange. - </doc> - <rule name="typed" on-failure="not-allowed"> - <doc> - Exchanges cannot be redeclared with different types. The - client MUST not - attempt to redeclare an existing exchange with a - different type than used - in the original Exchange.Declare method. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - <rule name="support" on-failure="command-invalid"> - <doc> - The client MUST NOT attempt to declare an exchange with - a type that the - server does not support. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - - <field name="passive" domain="bit" label="do not create exchange"> - <doc> - If set, the server will reply with Declare-Ok if the - exchange already - exists with the same name, and raise an error if not. The - client can - use this to check whether an exchange exists without - modifying the - server state. When set, all other method fields except name - and no-wait - are ignored. A declare with both passive and no-wait has no - effect. - Arguments are compared for semantic equivalence. - </doc> - <rule name="not-found"> - <doc> - If set, and the exchange does not already exist, the - server MUST - raise a channel exception with reply code 404 (not - found). - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - <rule name="equivalent"> - <doc> - If not set and the exchange exists, the server MUST - check that the - existing exchange has the same values for type, durable, - and arguments - fields. The server MUST respond with Declare-Ok if the - requested - exchange matches these fields, and MUST raise a channel - exception if - not. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - - <field name="durable" domain="bit" - label="request a durable exchange"> - <doc> - If set when creating a new exchange, the exchange will be - marked as durable. - Durable exchanges remain active when a server restarts. - Non-durable exchanges - (transient exchanges) are purged if/when a server restarts. - </doc> - <rule name="support"> - <doc> - The server MUST support both durable and transient - exchanges. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - - <!-- Deprecated: "auto-delete", must be zero --> - <field name="reserved-2" type="bit" reserved="1"/> - <!-- Deprecated: "internal", must be zero --> - <field name="reserved-3" type="bit" reserved="1"/> - <field name="no-wait" domain="no-wait"/> - - <field name="arguments" domain="table" - label="arguments for declaration"> - <doc> - A set of arguments for the declaration. The syntax and - semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name="declare-ok" synchronous="1" index="11" - label="confirm exchange declaration"> - <doc> - This method confirms a Declare method and confirms the name of - the exchange, - essential for automatically-named exchanges. - </doc> - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="delete" synchronous="1" index="20" - label="delete an exchange"> - <doc> - This method deletes an exchange. When an exchange is deleted all - queue bindings on - the exchange are cancelled. - </doc> - - <chassis name="server" implement="MUST"/> - <response name="delete-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="exchange" domain="exchange-name"> - <rule name="exists" on-failure="not-found"> - <doc> - The client MUST NOT attempt to delete an exchange that - does not exist. - </doc> - </rule> - <assert check="notnull"/> - </field> - - <field name="if-unused" domain="bit" label="delete only if unused"> - <doc> - If set, the server will only delete the exchange if it has - no queue bindings. If - the exchange has queue bindings the server does not delete - it but raises a - channel exception instead. - </doc> - <rule name="in-use" on-failure="precondition-failed"> - <doc> - The server MUST NOT delete an exchange that has bindings - on it, if the if-unused - field is true. - </doc> - <doc type="scenario"> - The client declares an exchange, binds a queue to it, - then tries to delete it - setting if-unused to true. - </doc> - </rule> - </field> - - <field name="no-wait" domain="no-wait"/> - </method> - - <method name="delete-ok" synchronous="1" index="21" - label="confirm deletion of an exchange"> - <doc>This method confirms the deletion of an exchange.</doc> - <chassis name="client" implement="MUST"/> - </method> - </class> - - <!-- == QUEUE ============================================================ --> - - <class name="queue" handler="channel" index="50" label="work with queues"> - <doc> - Queues store and forward messages. Queues can be configured in the - server or created at - runtime. Queues must be attached to at least one exchange in order - to receive messages - from publishers. - </doc> - - <doc type="grammar"> - queue = C:DECLARE S:DECLARE-OK - / C:BIND S:BIND-OK - / C:UNBIND S:UNBIND-OK - / C:PURGE S:PURGE-OK - / C:DELETE S:DELETE-OK - </doc> - - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MUST"/> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="declare" synchronous="1" index="10" - label="declare queue, create if needed"> - <doc> - This method creates or checks a queue. When creating a new queue - the client can - specify various properties that control the durability of the - queue and its - contents, and the level of sharing for the queue. - </doc> - - <rule name="default-binding"> - <doc> - The server MUST create a default binding for a - newly-declared queue to the - default exchange, which is an exchange of type 'direct' and - use the queue - name as the routing key. - </doc> - <doc type="scenario"> - Client declares a new queue, and then without explicitly - binding it to an - exchange, attempts to send a message through the default - exchange binding, - i.e. publish a message to the empty exchange, with the queue - name as routing - key. - </doc> - </rule> - - <rule name="minimum-queues"> - <doc> - The server SHOULD support a minimum of 256 queues per - virtual host and ideally, - impose no limit except as defined by available resources. - </doc> - <doc type="scenario"> - Client attempts to declare as many queues as it can until - the server reports - an error. The resulting count must at least be 256. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - <response name="declare-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <rule name="default-name"> - <doc> - The queue name MAY be empty, in which case the server - MUST create a new - queue with a unique generated name and return this to - the client in the - Declare-Ok method. - </doc> - <doc type="scenario"> - Client attempts to declare several queues with an empty - name. The client then - verifies that the server-assigned names are unique and - different. - </doc> - </rule> - <rule name="reserved" on-failure="access-refused"> - <doc> - Queue names starting with "amq." are reserved for - pre-declared and - standardised queues. The client MAY declare a queue - starting with - "amq." if the passive option is set, or the queue - already exists. - </doc> - <doc type="scenario"> - The client attempts to declare a non-existing queue - starting with - "amq." and with the passive option set to zero. - </doc> - </rule> - <rule name="syntax" on-failure="precondition-failed"> - <doc> - The queue name can be empty, or a sequence of these - characters: - letters, digits, hyphen, underscore, period, or colon. - </doc> - <doc type="scenario"> - The client attempts to declare a queue with an illegal - name. - </doc> - </rule> - </field> - - <field name="passive" domain="bit" label="do not create queue"> - <doc> - If set, the server will reply with Declare-Ok if the queue - already - exists with the same name, and raise an error if not. The - client can - use this to check whether a queue exists without modifying - the - server state. When set, all other method fields except name - and no-wait - are ignored. A declare with both passive and no-wait has no - effect. - Arguments are compared for semantic equivalence. - </doc> - <rule name="passive" on-failure="not-found"> - <doc> - The client MAY ask the server to assert that a queue - exists without - creating the queue if not. If the queue does not exist, - the server - treats this as a failure. - </doc> - <doc type="scenario"> - Client declares an existing queue with the passive - option and expects - the server to respond with a declare-ok. Client then - attempts to declare - a non-existent queue with the passive option, and the - server must close - the channel with the correct reply-code. - </doc> - </rule> - <rule name="equivalent"> - <doc> - If not set and the queue exists, the server MUST check - that the - existing queue has the same values for durable, - exclusive, auto-delete, - and arguments fields. The server MUST respond with - Declare-Ok if the - requested queue matches these fields, and MUST raise a - channel exception - if not. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - - <field name="durable" domain="bit" label="request a durable queue"> - <doc> - If set when creating a new queue, the queue will be marked - as durable. Durable - queues remain active when a server restarts. Non-durable - queues (transient - queues) are purged if/when a server restarts. Note that - durable queues do not - necessarily hold persistent messages, although it does not - make sense to send - persistent messages to a transient queue. - </doc> - - <rule name="persistence"> - <doc>The server MUST recreate the durable queue after a - restart. - </doc> - - <doc type="scenario"> - Client declares a durable queue. The server is then - restarted. The client - then attempts to send a message to the queue. The - message should be successfully - delivered. - </doc> - </rule> - - <rule name="types"> - <doc>The server MUST support both durable and transient - queues. - </doc> - <doc type="scenario"> - A client declares two named queues, one durable and one - transient. - </doc> - </rule> - </field> - - <field name="exclusive" domain="bit" - label="request an exclusive queue"> - <doc> - Exclusive queues may only be accessed by the current - connection, and are - deleted when that connection closes. Passive declaration of - an exclusive - queue by other connections are not allowed. - </doc> - - <rule name="types"> - <doc> - The server MUST support both exclusive (private) and - non-exclusive (shared) - queues. - </doc> - <doc type="scenario"> - A client declares two named queues, one exclusive and - one non-exclusive. - </doc> - </rule> - - <rule name="exclusive" on-failure="resource-locked"> - <doc> - The client MAY NOT attempt to use a queue that was - declared as exclusive - by another still-open connection. - </doc> - <doc type="scenario"> - One client declares an exclusive queue. A second client - on a different - connection attempts to declare, bind, consume, purge, - delete, or declare - a queue of the same name. - </doc> - </rule> - </field> - - <field name="auto-delete" domain="bit" - label="auto-delete queue when unused"> - <doc> - If set, the queue is deleted when all consumers have - finished using it. The last - consumer can be cancelled either explicitly or because its - channel is closed. If - there was no consumer ever on the queue, it won't be - deleted. Applications can - explicitly delete auto-delete queues using the Delete method - as normal. - </doc> - - <rule name="pre-existence"> - <doc> - The server MUST ignore the auto-delete field if the - queue already exists. - </doc> - <doc type="scenario"> - Client declares two named queues, one as auto-delete and - one explicit-delete. - Client then attempts to declare the two queues using the - same names again, - but reversing the value of the auto-delete field in each - case. Verify that the - queues still exist with the original auto-delete flag - values. - </doc> - </rule> - </field> - - <field name="no-wait" domain="no-wait"/> - - <field name="arguments" domain="table" - label="arguments for declaration"> - <doc> - A set of arguments for the declaration. The syntax and - semantics of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name="declare-ok" synchronous="1" index="11" - label="confirms a queue definition"> - <doc> - This method confirms a Declare method and confirms the name of - the queue, essential - for automatically-named queues. - </doc> - - <chassis name="client" implement="MUST"/> - - <field name="queue" domain="queue-name"> - <doc> - Reports the name of the queue. If the server generated a - queue name, this field - contains that name. - </doc> - <assert check="notnull"/> - </field> - - <field name="message-count" domain="message-count"/> - - <field name="consumer-count" domain="long" - label="number of consumers"> - <doc> - Reports the number of active consumers for the queue. Note - that consumers can - suspend activity (Channel.Flow) in which case they do not - appear in this count. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="bind" synchronous="1" index="20" - label="bind queue to an exchange"> - <doc> - This method binds a queue to an exchange. Until a queue is bound - it will not - receive any messages. In a classic messaging model, - store-and-forward queues - are bound to a direct exchange and subscription queues are bound - to a topic - exchange. - </doc> - - <rule name="duplicates"> - <doc> - A server MUST allow ignore duplicate bindings - that is, two - or more bind - methods for a specific queue, with identical arguments - - without treating these - as an error. - </doc> - <doc type="scenario"> - A client binds a named queue to an exchange. The client then - repeats the bind - (with identical arguments). - </doc> - </rule> - - <rule name="unique"> - <doc> - A server MUST not deliver the same message more than once to - a queue, even if - the queue has multiple bindings that match the message. - </doc> - <doc type="scenario"> - A client declares a named queue and binds it using multiple - bindings to the - amq.topic exchange. The client then publishes a message that - matches all its - bindings. - </doc> - </rule> - - <rule name="transient-exchange"> - <doc> - The server MUST allow a durable queue to bind to a transient - exchange. - </doc> - <doc type="scenario"> - A client declares a transient exchange. The client then - declares a named durable - queue and then attempts to bind the transient exchange to - the durable queue. - </doc> - </rule> - - <rule name="durable-exchange"> - <doc> - Bindings of durable queues to durable exchanges are - automatically durable - and the server MUST restore such bindings after a server - restart. - </doc> - <doc type="scenario"> - A server declares a named durable queue and binds it to a - durable exchange. The - server is restarted. The client then attempts to use the - queue/exchange combination. - </doc> - </rule> - - <rule name="binding-count"> - <doc> - The server SHOULD support at least 4 bindings per queue, and - ideally, impose no - limit except as defined by available resources. - </doc> - <doc type="scenario"> - A client declares a named queue and attempts to bind it to 4 - different - exchanges. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - - <response name="bind-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <doc>Specifies the name of the queue to bind.</doc> - <rule name="queue-known" on-failure="not-found"> - <doc> - The client MUST either specify a queue name or have - previously declared a - queue on the same channel - </doc> - <doc type="scenario"> - The client opens a channel and attempts to bind an - unnamed queue. - </doc> - </rule> - <rule name="must-exist" on-failure="not-found"> - <doc> - The client MUST NOT attempt to bind a queue that does - not exist. - </doc> - <doc type="scenario"> - The client attempts to bind a non-existent queue. - </doc> - </rule> - </field> - - <field name="exchange" domain="exchange-name" - label="name of the exchange to bind to"> - <rule name="exchange-existence" on-failure="not-found"> - <doc> - A client MUST NOT be allowed to bind a queue to a - non-existent exchange. - </doc> - <doc type="scenario"> - A client attempts to bind an named queue to a undeclared - exchange. - </doc> - </rule> - <rule name="default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type="scenario"> - The client declares a queue and binds it to a blank - exchange name. - </doc> - </rule> - </field> - - <field name="routing-key" domain="shortstr" - label="message routing key"> - <doc> - Specifies the routing key for the binding. The routing key - is used for routing - messages depending on the exchange configuration. Not all - exchanges use a - routing key - refer to the specific exchange documentation. - If the queue name - is empty, the server uses the last queue declared on the - channel. If the - routing key is also empty, the server uses this queue name - for the routing - key as well. If the queue name is provided but the routing - key is empty, the - server does the binding with that empty routing key. The - meaning of empty - routing keys depends on the exchange implementation. - </doc> - <rule name="direct-exchange-key-matching"> - <doc> - If a message queue binds to a direct exchange using - routing key K and a - publisher sends the exchange a message with routing key - R, then the message - MUST be passed to the message queue if K = R. - </doc> - </rule> - </field> - - <field name="no-wait" domain="no-wait"/> - - <field name="arguments" domain="table" - label="arguments for binding"> - <doc> - A set of arguments for the binding. The syntax and semantics - of these arguments - depends on the exchange class. - </doc> - </field> - </method> - - <method name="bind-ok" synchronous="1" index="21" - label="confirm bind successful"> - <doc>This method confirms that the bind was successful.</doc> - - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="unbind" synchronous="1" index="50" - label="unbind a queue from an exchange"> - <doc>This method unbinds a queue from an exchange.</doc> - <rule name="01"> - <doc>If a unbind fails, the server MUST raise a connection - exception. - </doc> - </rule> - <chassis name="server" implement="MUST"/> - <response name="unbind-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <doc>Specifies the name of the queue to unbind.</doc> - <rule name="queue-known" on-failure="not-found"> - <doc> - The client MUST either specify a queue name or have - previously declared a - queue on the same channel - </doc> - <doc type="scenario"> - The client opens a channel and attempts to unbind an - unnamed queue. - </doc> - </rule> - <rule name="must-exist" on-failure="not-found"> - <doc> - The client MUST NOT attempt to unbind a queue that does - not exist. - </doc> - <doc type="scenario"> - The client attempts to unbind a non-existent queue. - </doc> - </rule> - </field> - - <field name="exchange" domain="exchange-name"> - <doc>The name of the exchange to unbind from.</doc> - <rule name="must-exist" on-failure="not-found"> - <doc> - The client MUST NOT attempt to unbind a queue from an - exchange that - does not exist. - </doc> - <doc type="scenario"> - The client attempts to unbind a queue from a - non-existent exchange. - </doc> - </rule> - <rule name="default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type="scenario"> - The client declares a queue and binds it to a blank - exchange name. - </doc> - </rule> - </field> - - <field name="routing-key" domain="shortstr" - label="routing key of binding"> - <doc>Specifies the routing key of the binding to unbind.</doc> - </field> - - <field name="arguments" domain="table" label="arguments of binding"> - <doc>Specifies the arguments of the binding to unbind.</doc> - </field> - </method> - - <method name="unbind-ok" synchronous="1" index="51" - label="confirm unbind successful"> - <doc>This method confirms that the unbind was successful.</doc> - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="purge" synchronous="1" index="30" label="purge a queue"> - <doc> - This method removes all messages from a queue which are not - awaiting - acknowledgment. - </doc> - - <rule name="02"> - <doc> - The server MUST NOT purge messages that have already been - sent to a client - but not yet acknowledged. - </doc> - </rule> - - <rule name="03"> - <doc> - The server MAY implement a purge queue or log that allows - system administrators - to recover accidentally-purged messages. The server SHOULD - NOT keep purged - messages in the same storage spaces as the live messages - since the volumes of - purged messages may get very large. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - - <response name="purge-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <doc>Specifies the name of the queue to purge.</doc> - <rule name="queue-known" on-failure="not-found"> - <doc> - The client MUST either specify a queue name or have - previously declared a - queue on the same channel - </doc> - <doc type="scenario"> - The client opens a channel and attempts to purge an - unnamed queue. - </doc> - </rule> - <rule name="must-exist" on-failure="not-found"> - <doc> - The client MUST NOT attempt to purge a queue that does - not exist. - </doc> - <doc type="scenario"> - The client attempts to purge a non-existent queue. - </doc> - </rule> - </field> - - <field name="no-wait" domain="no-wait"/> - </method> - - <method name="purge-ok" synchronous="1" index="31" - label="confirms a queue purge"> - <doc>This method confirms the purge of a queue.</doc> - - <chassis name="client" implement="MUST"/> - - <field name="message-count" domain="message-count"> - <doc> - Reports the number of messages purged. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="delete" synchronous="1" index="40" label="delete a queue"> - <doc> - This method deletes a queue. When a queue is deleted any pending - messages are sent - to a dead-letter queue if this is defined in the server - configuration, and all - consumers on the queue are cancelled. - </doc> - - <rule name="01"> - <doc> - The server SHOULD use a dead-letter queue to hold messages - that were pending on - a deleted queue, and MAY provide facilities for a system - administrator to move - these messages back to an active queue. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - - <response name="delete-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <doc>Specifies the name of the queue to delete.</doc> - <rule name="queue-known" on-failure="not-found"> - <doc> - The client MUST either specify a queue name or have - previously declared a - queue on the same channel - </doc> - <doc type="scenario"> - The client opens a channel and attempts to delete an - unnamed queue. - </doc> - </rule> - <rule name="must-exist" on-failure="not-found"> - <doc> - The client MUST NOT attempt to delete a queue that does - not exist. - </doc> - <doc type="scenario"> - The client attempts to delete a non-existent queue. - </doc> - </rule> - </field> - - <field name="if-unused" domain="bit" label="delete only if unused"> - <doc> - If set, the server will only delete the queue if it has no - consumers. If the - queue has consumers the server does does not delete it but - raises a channel - exception instead. - </doc> - <rule name="in-use" on-failure="precondition-failed"> - <doc> - The server MUST NOT delete a queue that has consumers on - it, if the if-unused - field is true. - </doc> - <doc type="scenario"> - The client declares a queue, and consumes from it, then - tries to delete it - setting if-unused to true. - </doc> - </rule> - </field> - - <field name="if-empty" domain="bit" label="delete only if empty"> - <doc> - If set, the server will only delete the queue if it has no - messages. - </doc> - <rule name="not-empty" on-failure="precondition-failed"> - <doc> - The server MUST NOT delete a queue that has messages on - it, if the - if-empty field is true. - </doc> - <doc type="scenario"> - The client declares a queue, binds it and publishes some - messages into it, - then tries to delete it setting if-empty to true. - </doc> - </rule> - </field> - - <field name="no-wait" domain="no-wait"/> - </method> - - <method name="delete-ok" synchronous="1" index="41" - label="confirm deletion of a queue"> - <doc>This method confirms the deletion of a queue.</doc> - - <chassis name="client" implement="MUST"/> - - <field name="message-count" domain="message-count"> - <doc>Reports the number of messages deleted.</doc> - </field> - </method> - </class> - - <!-- == BASIC ============================================================ --> - - <class name="basic" handler="channel" index="60" - label="work with basic content"> - <doc> - The Basic class provides methods that support an industry-standard - messaging model. - </doc> - - <doc type="grammar"> - basic = C:QOS S:QOS-OK - / C:CONSUME S:CONSUME-OK - / C:CANCEL S:CANCEL-OK - / C:PUBLISH content - / S:RETURN content - / S:DELIVER content - / C:GET ( S:GET-OK content / S:GET-EMPTY ) - / C:ACK - / C:REJECT - / C:RECOVER-ASYNC - / C:RECOVER S:RECOVER-OK - </doc> - - <chassis name="server" implement="MUST"/> - <chassis name="client" implement="MAY"/> - - <rule name="01"> - <doc> - The server SHOULD respect the persistent property of basic - messages and - SHOULD make a best-effort to hold persistent basic messages on a - reliable - storage mechanism. - </doc> - <doc type="scenario"> - Send a persistent message to queue, stop server, restart server - and then - verify whether message is still present. Assumes that queues are - durable. - Persistence without durable queues makes no sense. - </doc> - </rule> - - <rule name="02"> - <doc> - The server MUST NOT discard a persistent basic message in case - of a queue - overflow. - </doc> - <doc type="scenario"> - Declare a queue overflow situation with persistent messages and - verify that - messages do not get lost (presumably the server will write them - to disk). - </doc> - </rule> - - <rule name="03"> - <doc> - The server MAY use the Channel.Flow method to slow or stop a - basic message - publisher when necessary. - </doc> - <doc type="scenario"> - Declare a queue overflow situation with non-persistent messages - and verify - whether the server responds with Channel.Flow or not. Repeat - with persistent - messages. - </doc> - </rule> - - <rule name="04"> - <doc> - The server MAY overflow non-persistent basic messages to - persistent - storage. - </doc> - <!-- Test scenario: untestable --> - </rule> - - <rule name="05"> - <doc> - The server MAY discard or dead-letter non-persistent basic - messages on a - priority basis if the queue size exceeds some configured limit. - </doc> - <!-- Test scenario: untestable --> - </rule> - - <rule name="06"> - <doc> - The server MUST implement at least 2 priority levels for basic - messages, - where priorities 0-4 and 5-9 are treated as two distinct levels. - </doc> - <doc type="scenario"> - Send a number of priority 0 messages to a queue. Send one - priority 9 - message. Consume messages from the queue and verify that the - first message - received was priority 9. - </doc> - </rule> - - <rule name="07"> - <doc> - The server MAY implement up to 10 priority levels. - </doc> - <doc type="scenario"> - Send a number of messages with mixed priorities to a queue, so - that all - priority values from 0 to 9 are exercised. A good scenario would - be ten - messages in low-to-high priority. Consume from queue and verify - how many - priority levels emerge. - </doc> - </rule> - - <rule name="08"> - <doc> - The server MUST deliver messages of the same priority in order - irrespective of - their individual persistence. - </doc> - <doc type="scenario"> - Send a set of messages with the same priority but different - persistence - settings to a queue. Consume and verify that messages arrive in - same order - as originally published. - </doc> - </rule> - - <rule name="09"> - <doc> - The server MUST support un-acknowledged delivery of Basic - content, i.e. - consumers with the no-ack field set to TRUE. - </doc> - </rule> - - <rule name="10"> - <doc> - The server MUST support explicitly acknowledged delivery of - Basic content, - i.e. consumers with the no-ack field set to FALSE. - </doc> - <doc type="scenario"> - Declare a queue and a consumer using explicit acknowledgements. - Publish a - set of messages to the queue. Consume the messages but - acknowledge only - half of them. Disconnect and reconnect, and consume from the - queue. - Verify that the remaining messages are received. - </doc> - </rule> - - <!-- These are the properties for a Basic content --> - - <!-- MIME typing --> - <field name="content-type" domain="shortstr" label="MIME content type"/> - <!-- MIME typing --> - <field name="content-encoding" domain="shortstr" - label="MIME content encoding"/> - <!-- For applications, and for header exchange routing --> - <field name="headers" domain="table" - label="message header field table"/> - <!-- For queues that implement persistence --> - <field name="delivery-mode" domain="octet" - label="non-persistent (1) or persistent (2)"/> - <!-- For queues that implement priorities --> - <field name="priority" domain="octet" label="message priority, 0 to 9"/> - <!-- For application use, no formal behaviour --> - <field name="correlation-id" domain="shortstr" - label="application correlation identifier"/> - <!-- For application use, no formal behaviour but may hold the - name of a private response queue, when used in request messages --> - <field name="reply-to" domain="shortstr" label="address to reply to"/> - <!-- For implementation use, no formal behaviour --> - <field name="expiration" domain="shortstr" - label="message expiration specification"/> - <!-- For application use, no formal behaviour --> - <field name="message-id" domain="shortstr" - label="application message identifier"/> - <!-- For application use, no formal behaviour --> - <field name="timestamp" domain="timestamp" label="message timestamp"/> - <!-- For application use, no formal behaviour --> - <field name="type" domain="shortstr" label="message type name"/> - <!-- For application use, no formal behaviour --> - <field name="user-id" domain="shortstr" label="creating user id"/> - <!-- For application use, no formal behaviour --> - <field name="app-id" domain="shortstr" label="creating application id"/> - <!-- Deprecated, was old cluster-id property --> - <field name="reserved" domain="shortstr" - label="reserved, must be empty"/> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="qos" synchronous="1" index="10" - label="specify quality of service"> - <doc> - This method requests a specific quality of service. The QoS can - be specified for the - current channel or for all channels on the connection. The - particular properties and - semantics of a qos method always depend on the content class - semantics. Though the - qos method could in principle apply to both peers, it is - currently meaningful only - for the server. - </doc> - - <chassis name="server" implement="MUST"/> - <response name="qos-ok"/> - - <field name="prefetch-size" domain="long" - label="prefetch window in octets"> - <doc> - The client can request that messages be sent in advance so - that when the client - finishes processing a message, the following message is - already held locally, - rather than needing to be sent down the channel. Prefetching - gives a performance - improvement. This field specifies the prefetch window size - in octets. The server - will send a message in advance if it is equal to or smaller - in size than the - available prefetch size (and also falls into other prefetch - limits). May be set - to zero, meaning "no specific limit", although other - prefetch limits may still - apply. The prefetch-size is ignored if the no-ack option is - set. - </doc> - <rule name="01"> - <doc> - The server MUST ignore this setting when the client is - not processing any - messages - i.e. the prefetch size does not limit the - transfer of single - messages to a client, only the sending in advance of - more messages while - the client still has one or more unacknowledged - messages. - </doc> - <doc type="scenario"> - Define a QoS prefetch-size limit and send a single - message that exceeds - that limit. Verify that the message arrives correctly. - </doc> - </rule> - </field> - - <field name="prefetch-count" domain="short" - label="prefetch window in messages"> - <doc> - Specifies a prefetch window in terms of whole messages. This - field may be used - in combination with the prefetch-size field; a message will - only be sent in - advance if both prefetch windows (and those at the channel - and connection level) - allow it. The prefetch-count is ignored if the no-ack option - is set. - </doc> - <rule name="01"> - <doc> - The server may send less data in advance than allowed by - the client's - specified prefetch windows but it MUST NOT send more. - </doc> - <doc type="scenario"> - Define a QoS prefetch-size limit and a prefetch-count - limit greater than - one. Send multiple messages that exceed the prefetch - size. Verify that - no more than one message arrives at once. - </doc> - </rule> - </field> - - <field name="global" domain="bit" - label="apply to entire connection"> - <doc> - By default the QoS settings apply to the current channel - only. If this field is - set, they are applied to the entire connection. - </doc> - </field> - </method> - - <method name="qos-ok" synchronous="1" index="11" - label="confirm the requested qos"> - <doc> - This method tells the client that the requested QoS levels could - be handled by the - server. The requested QoS applies to all active consumers until - a new QoS is - defined. - </doc> - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="consume" synchronous="1" index="20" - label="start a queue consumer"> - <doc> - This method asks the server to start a "consumer", which is a - transient request for - messages from a specific queue. Consumers last as long as the - channel they were - declared on, or until the client cancels them. - </doc> - - <rule name="01"> - <doc> - The server SHOULD support at least 16 consumers per queue, - and ideally, impose - no limit except as defined by available resources. - </doc> - <doc type="scenario"> - Declare a queue and create consumers on that queue until the - server closes the - connection. Verify that the number of consumers created was - at least sixteen - and report the total number. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - <response name="consume-ok"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <doc>Specifies the name of the queue to consume from.</doc> - </field> - - <field name="consumer-tag" domain="consumer-tag"> - <doc> - Specifies the identifier for the consumer. The consumer tag - is local to a - channel, so two clients can use the same consumer tags. If - this field is - empty the server will generate a unique tag. - </doc> - <rule name="01" on-failure="not-allowed"> - <doc> - The client MUST NOT specify a tag that refers to an - existing consumer. - </doc> - <doc type="scenario"> - Attempt to create two consumers with the same non-empty - tag, on the - same channel. - </doc> - </rule> - <rule name="02" on-failure="not-allowed"> - <doc> - The consumer tag is valid only within the channel from - which the - consumer was created. I.e. a client MUST NOT create a - consumer in one - channel and then use it in another. - </doc> - <doc type="scenario"> - Attempt to create a consumer in one channel, then use in - another channel, - in which consumers have also been created (to test that - the server uses - unique consumer tags). - </doc> - </rule> - </field> - - <field name="no-local" domain="no-local"/> - - <field name="no-ack" domain="no-ack"/> - - <field name="exclusive" domain="bit" - label="request exclusive access"> - <doc> - Request exclusive consumer access, meaning only this - consumer can access the - queue. - </doc> - - <rule name="01" on-failure="access-refused"> - <doc> - The client MAY NOT gain exclusive access to a queue that - already has - active consumers. - </doc> - <doc type="scenario"> - Open two connections to a server, and in one connection - declare a shared - (non-exclusive) queue and then consume from the queue. - In the second - connection attempt to consume from the same queue using - the exclusive - option. - </doc> - </rule> - </field> - - <field name="no-wait" domain="no-wait"/> - - <field name="arguments" domain="table" - label="arguments for declaration"> - <doc> - A set of arguments for the consume. The syntax and semantics - of these - arguments depends on the server implementation. - </doc> - </field> - </method> - - <method name="consume-ok" synchronous="1" index="21" - label="confirm a new consumer"> - <doc> - The server provides the client with a consumer tag, which is - used by the client - for methods called on the consumer at a later stage. - </doc> - <chassis name="client" implement="MUST"/> - <field name="consumer-tag" domain="consumer-tag"> - <doc> - Holds the consumer tag specified by the client or provided - by the server. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="cancel" synchronous="1" index="30" - label="end a queue consumer"> - <doc> - This method cancels a consumer. This does not affect already - delivered - messages, but it does mean the server will not send any more - messages for - that consumer. The client may receive an arbitrary number of - messages in - between sending the cancel method and receiving the cancel-ok - reply. - </doc> - - <rule name="01"> - <doc> - If the queue does not exist the server MUST ignore the - cancel method, so - long as the consumer tag is valid for that channel. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - <response name="cancel-ok"/> - - <field name="consumer-tag" domain="consumer-tag"/> - <field name="no-wait" domain="no-wait"/> - </method> - - <method name="cancel-ok" synchronous="1" index="31" - label="confirm a cancelled consumer"> - <doc> - This method confirms that the cancellation was completed. - </doc> - <chassis name="client" implement="MUST"/> - <field name="consumer-tag" domain="consumer-tag"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="publish" content="1" index="40" label="publish a message"> - <doc> - This method publishes a message to a specific exchange. The - message will be routed - to queues as defined by the exchange configuration and - distributed to any active - consumers when the transaction, if any, is committed. - </doc> - - <chassis name="server" implement="MUST"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="exchange" domain="exchange-name"> - <doc> - Specifies the name of the exchange to publish to. The - exchange name can be - empty, meaning the default exchange. If the exchange name is - specified, and that - exchange does not exist, the server will raise a channel - exception. - </doc> - - <rule name="must-exist" on-failure="not-found"> - <doc> - The client MUST NOT attempt to publish a content to an - exchange that - does not exist. - </doc> - <doc type="scenario"> - The client attempts to publish a content to a - non-existent exchange. - </doc> - </rule> - <rule name="default-exchange"> - <doc> - The server MUST accept a blank exchange name to mean the - default exchange. - </doc> - <doc type="scenario"> - The client declares a queue and binds it to a blank - exchange name. - </doc> - </rule> - <rule name="02"> - <doc> - If the exchange was declared as an internal exchange, - the server MUST raise - a channel exception with a reply code 403 (access - refused). - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - - <rule name="03"> - <doc> - The exchange MAY refuse basic content in which case it - MUST raise a channel - exception with reply code 540 (not implemented). - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - - <field name="routing-key" domain="shortstr" - label="Message routing key"> - <doc> - Specifies the routing key for the message. The routing key - is used for routing - messages depending on the exchange configuration. - </doc> - </field> - - <field name="mandatory" domain="bit" - label="indicate mandatory routing"> - <doc> - This flag tells the server how to react if the message - cannot be routed to a - queue. If this flag is set, the server will return an - unroutable message with a - Return method. If this flag is zero, the server silently - drops the message. - </doc> - - <rule name="01"> - <doc> - The server SHOULD implement the mandatory flag. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - - <field name="immediate" domain="bit" - label="request immediate delivery"> - <doc> - This flag tells the server how to react if the message - cannot be routed to a - queue consumer immediately. If this flag is set, the server - will return an - undeliverable message with a Return method. If this flag is - zero, the server - will queue the message, but with no guarantee that it will - ever be consumed. - </doc> - - <rule name="01"> - <doc> - The server SHOULD implement the immediate flag. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <method name="return" content="1" index="50" - label="return a failed message"> - <doc> - This method returns an undeliverable message that was published - with the "immediate" - flag set, or an unroutable message published with the - "mandatory" flag set. The - reply code and text provide information about the reason that - the message was - undeliverable. - </doc> - - <chassis name="client" implement="MUST"/> - - <field name="reply-code" domain="reply-code"/> - <field name="reply-text" domain="reply-text"/> - - <field name="exchange" domain="exchange-name"> - <doc> - Specifies the name of the exchange that the message was - originally published - to. May be empty, meaning the default exchange. - </doc> - </field> - - <field name="routing-key" domain="shortstr" - label="Message routing key"> - <doc> - Specifies the routing key name specified when the message - was published. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="deliver" content="1" index="60" - label="notify the client of a consumer message"> - <doc> - This method delivers a message to the client, via a consumer. In - the asynchronous - message delivery model, the client starts a consumer using the - Consume method, then - the server responds with Deliver methods as and when messages - arrive for that - consumer. - </doc> - - <rule name="01"> - <doc> - The server SHOULD track the number of times a message has - been delivered to - clients and when a message is redelivered a certain number - of times - e.g. 5 - times - without being acknowledged, the server SHOULD - consider the message to be - unprocessable (possibly causing client applications to - abort), and move the - message to a dead letter queue. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - - <chassis name="client" implement="MUST"/> - - <field name="consumer-tag" domain="consumer-tag"/> - <field name="delivery-tag" domain="delivery-tag"/> - <field name="redelivered" domain="redelivered"/> - - <field name="exchange" domain="exchange-name"> - <doc> - Specifies the name of the exchange that the message was - originally published to. - May be empty, indicating the default exchange. - </doc> - </field> - - <field name="routing-key" domain="shortstr" - label="Message routing key"> - <doc>Specifies the routing key name specified when the message - was published. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="get" synchronous="1" index="70" - label="direct access to a queue"> - <doc> - This method provides a direct access to the messages in a queue - using a synchronous - dialogue that is designed for specific types of application - where synchronous - functionality is more important than performance. - </doc> - - <response name="get-ok"/> - <response name="get-empty"/> - <chassis name="server" implement="MUST"/> - - <!-- Deprecated: "ticket", must be zero --> - <field name="reserved-1" type="short" reserved="1"/> - - <field name="queue" domain="queue-name"> - <doc>Specifies the name of the queue to get a message from. - </doc> - </field> - <field name="no-ack" domain="no-ack"/> - </method> - - <method name="get-ok" synchronous="1" content="1" index="71" - label="provide client with a message"> - <doc> - This method delivers a message to the client following a get - method. A message - delivered by 'get-ok' must be acknowledged unless the no-ack - option was set in the - get method. - </doc> - - <chassis name="client" implement="MAY"/> - - <field name="delivery-tag" domain="delivery-tag"/> - <field name="redelivered" domain="redelivered"/> - <field name="exchange" domain="exchange-name"> - <doc> - Specifies the name of the exchange that the message was - originally published to. - If empty, the message was published to the default exchange. - </doc> - </field> - - <field name="routing-key" domain="shortstr" - label="Message routing key"> - <doc>Specifies the routing key name specified when the message - was published. - </doc> - </field> - - <field name="message-count" domain="message-count"/> - </method> - - <method name="get-empty" synchronous="1" index="72" - label="indicate no messages available"> - <doc> - This method tells the client that the queue has no messages - available for the - client. - </doc> - <chassis name="client" implement="MAY"/> - <!-- Deprecated: "cluster-id", must be empty --> - <field name="reserved-1" type="shortstr" reserved="1"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="ack" index="80" label="acknowledge one or more messages"> - <doc> - This method acknowledges one or more messages delivered via the - Deliver or Get-Ok - methods. The client can ask to confirm a single message or a set - of messages up to - and including a specific message. - </doc> - - <chassis name="server" implement="MUST"/> - - <field name="delivery-tag" domain="delivery-tag"/> - <field name="multiple" domain="bit" - label="acknowledge multiple messages"> - <doc> - If set to 1, the delivery tag is treated as "up to and - including", so that the - client can acknowledge multiple messages with a single - method. If set to zero, - the delivery tag refers to a single message. If the multiple - field is 1, and the - delivery tag is zero, tells the server to acknowledge all - outstanding messages. - </doc> - <rule name="exists" on-failure="precondition-failed"> - <doc> - The server MUST validate that a non-zero delivery-tag - refers to a delivered - message, and raise a channel exception if this is not - the case. On a transacted - channel, this check MUST be done immediately and not - delayed until a Tx.Commit. - Specifically, a client MUST not acknowledge the same - message more than once. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="reject" index="90" label="reject an incoming message"> - <doc> - This method allows a client to reject a message. It can be used - to interrupt and - cancel large incoming messages, or return untreatable messages - to their original - queue. - </doc> - - <rule name="01"> - <doc> - The server SHOULD be capable of accepting and process the - Reject method while - sending message content with a Deliver or Get-Ok method. - I.e. the server should - read and process incoming methods while sending output - frames. To cancel a - partially-send content, the server sends a content body - frame of size 1 (i.e. - with no data except the frame-end octet). - </doc> - </rule> - - <rule name="02"> - <doc> - The server SHOULD interpret this method as meaning that the - client is unable to - process the message at this time. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - - <rule name="03"> - <doc> - The client MUST NOT use this method as a means of selecting - messages to process. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - - <chassis name="server" implement="MUST"/> - - <field name="delivery-tag" domain="delivery-tag"/> - - <field name="requeue" domain="bit" label="requeue the message"> - <doc> - If requeue is true, the server will attempt to requeue the - message. If requeue - is false or the requeue attempt fails the messages are - discarded or dead-lettered. - </doc> - - <rule name="01"> - <doc> - The server MUST NOT deliver the message to the same - client within the - context of the current channel. The recommended strategy - is to attempt to - deliver the message to an alternative consumer, and if - that is not possible, - to move the message to a dead-letter queue. The server - MAY use more - sophisticated tracking to hold the message on the queue - and redeliver it to - the same client at a later stage. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="recover-async" index="100" - label="redeliver unacknowledged messages" - deprecated="1"> - <doc> - This method asks the server to redeliver all unacknowledged - messages on a - specified channel. Zero or more messages may be redelivered. - This method - is deprecated in favour of the synchronous Recover/Recover-Ok. - </doc> - <rule name="01"> - <doc> - The server MUST set the redelivered flag on all messages - that are resent. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - <chassis name="server" implement="MAY"/> - <field name="requeue" domain="bit" label="requeue the message"> - <doc> - If this field is zero, the message will be redelivered to - the original - recipient. If this bit is 1, the server will attempt to - requeue the message, - potentially then delivering it to an alternative subscriber. - </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="recover" index="110" - label="redeliver unacknowledged messages"> - <doc> - This method asks the server to redeliver all unacknowledged - messages on a - specified channel. Zero or more messages may be redelivered. - This method - replaces the asynchronous Recover. - </doc> - <rule name="01"> - <doc> - The server MUST set the redelivered flag on all messages - that are resent. - </doc> - <doc type="scenario"> - TODO. - </doc> - </rule> - <chassis name="server" implement="MUST"/> - <field name="requeue" domain="bit" label="requeue the message"> - <doc> - If this field is zero, the message will be redelivered to - the original - recipient. If this bit is 1, the server will attempt to - requeue the message, - potentially then delivering it to an alternative subscriber. - </doc> - </field> - </method> - - <method name="recover-ok" synchronous="1" index="111" - label="confirm recovery"> - <doc> - This method acknowledges a Basic.Recover method. - </doc> - <chassis name="client" implement="MUST"/> - </method> - </class> - - <!-- == TX =============================================================== --> - - <class name="tx" handler="channel" index="90" - label="work with transactions"> - <doc> - The Tx class allows publish and ack operations to be batched into - atomic - units of work. The intention is that all publish and ack requests - issued - within a transaction will complete successfully or none of them - will. - Servers SHOULD implement atomic transactions at least where all - publish - or ack requests affect a single queue. Transactions that cover - multiple - queues may be non-atomic, given that queues can be created and - destroyed - asynchronously, and such events do not form part of any transaction. - Further, the behaviour of transactions with respect to the immediate - and - mandatory flags on Basic.Publish methods is not defined. - </doc> - - <rule name="not multiple queues"> - <doc> - Applications MUST NOT rely on the atomicity of transactions that - affect more than one queue. - </doc> - </rule> - <rule name="not immediate"> - <doc> - Applications MUST NOT rely on the behaviour of transactions that - include messages published with the immediate option. - </doc> - </rule> - <rule name="not mandatory"> - <doc> - Applications MUST NOT rely on the behaviour of transactions that - include messages published with the mandatory option. - </doc> - </rule> - - <doc type="grammar"> - tx = C:SELECT S:SELECT-OK - / C:COMMIT S:COMMIT-OK - / C:ROLLBACK S:ROLLBACK-OK - </doc> - - <chassis name="server" implement="SHOULD"/> - <chassis name="client" implement="MAY"/> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="select" synchronous="1" index="10" - label="select standard transaction mode"> - <doc> - This method sets the channel to use standard transactions. The - client must use this - method at least once on a channel before using the Commit or - Rollback methods. - </doc> - <chassis name="server" implement="MUST"/> - <response name="select-ok"/> - </method> - - <method name="select-ok" synchronous="1" index="11" - label="confirm transaction mode"> - <doc> - This method confirms to the client that the channel was - successfully set to use - standard transactions. - </doc> - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="commit" synchronous="1" index="20" - label="commit the current transaction"> - <doc> - This method commits all message publications and acknowledgments - performed in - the current transaction. A new transaction starts immediately - after a commit. - </doc> - <chassis name="server" implement="MUST"/> - <response name="commit-ok"/> - - <rule name="transacted" on-failure="precondition-failed"> - <doc> - The client MUST NOT use the Commit method on non-transacted - channels. - </doc> - <doc type="scenario"> - The client opens a channel and then uses Tx.Commit. - </doc> - </rule> - </method> - - <method name="commit-ok" synchronous="1" index="21" - label="confirm a successful commit"> - <doc> - This method confirms to the client that the commit succeeded. - Note that if a commit - fails, the server raises a channel exception. - </doc> - <chassis name="client" implement="MUST"/> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="rollback" synchronous="1" index="30" - label="abandon the current transaction"> - <doc> - This method abandons all message publications and - acknowledgments performed in - the current transaction. A new transaction starts immediately - after a rollback. - Note that unacked messages will not be automatically redelivered - by rollback; - if that is required an explicit recover call should be issued. - </doc> - <chassis name="server" implement="MUST"/> - <response name="rollback-ok"/> - - <rule name="transacted" on-failure="precondition-failed"> - <doc> - The client MUST NOT use the Rollback method on - non-transacted channels. - </doc> - <doc type="scenario"> - The client opens a channel and then uses Tx.Rollback. - </doc> - </rule> - </method> - - <method name="rollback-ok" synchronous="1" index="31" - label="confirm successful rollback"> - <doc> - This method confirms to the client that the rollback succeeded. - Note that if an - rollback fails, the server raises a channel exception. - </doc> - <chassis name="client" implement="MUST"/> - </method> - </class> - -</amqp> diff --git a/tests/test_clustering/test_things.py b/tests/test_clustering/test_things.py index 5c7878a29269826096d66d9dd6c734dbb89ff458..5e84db3763bb5362502fc8f51a72400df2ac929b 100644 --- a/tests/test_clustering/test_things.py +++ b/tests/test_clustering/test_things.py @@ -16,6 +16,13 @@ logging.basicConfig(level=logging.DEBUG) class TestConnecting(unittest.TestCase): + + def test_connection_blocked(self): + try: + from coolamqp.framing.definitions import ConnectionBlocked + except ImportError: + self.skipTest('ConnectionBlocked not supported!') + def test_on_fail(self): """Assert that on_fail doesn't fire if the cluster fails to connect""" q = {'failed': False}