diff --git a/coolamqp/attaches/publisher.py b/coolamqp/attaches/publisher.py index 9915dbaf381c711cf8395f303d22b44accc46aa9..ef2cdeece638ec9d820c9220f0f687bfe7146328 100644 --- a/coolamqp/attaches/publisher.py +++ b/coolamqp/attaches/publisher.py @@ -12,9 +12,9 @@ from __future__ import absolute_import, division, print_function import collections import logging -import warnings - +import struct import six +import warnings from coolamqp.framing.definitions import ChannelOpenOk, BasicPublish, Basic, \ BasicAck diff --git a/coolamqp/clustering/cluster.py b/coolamqp/clustering/cluster.py index 14262120343a8e28b74f3c8f8e1652c899913fb1..33d1bbeaeadc1a8f32cc20f9cdb813b83726d245 100644 --- a/coolamqp/clustering/cluster.py +++ b/coolamqp/clustering/cluster.py @@ -13,7 +13,8 @@ from coolamqp.attaches import Publisher, AttacheGroup, Consumer, Declarer from coolamqp.objects import Exchange from concurrent.futures import Future -from coolamqp.clustering.events import ConnectionLost, MessageReceived, NothingMuch +from coolamqp.clustering.events import ConnectionLost, MessageReceived, \ + NothingMuch logger = logging.getLogger(__name__) @@ -56,6 +57,7 @@ class Cluster(object): def decorated(): if not self.listener.terminating: on_fail() + self.on_fail = decorated else: self.on_fail = None @@ -101,7 +103,8 @@ class Cluster(object): """ fut = Future() fut.set_running_or_notify_cancel() # it's running right now - on_message = on_message or (lambda rmsg: self.events.put_nowait(MessageReceived(rmsg))) + on_message = on_message or ( + lambda rmsg: self.events.put_nowait(MessageReceived(rmsg))) con = Consumer(queue, on_message, future_to_notify=fut, *args, **kwargs) self.attache_group.add(con) return con, fut @@ -115,7 +118,8 @@ class Cluster(object): """ return self.decl.delete_queue(queue) - def publish(self, message, exchange=None, routing_key=u'', tx=None, confirm=None): + def publish(self, message, exchange=None, routing_key=u'', tx=None, + confirm=None): """ Publish a message. @@ -145,16 +149,20 @@ class Cluster(object): warnings.warn(u'Use confirm kwarg instead', DeprecationWarning) if confirm is not None: - raise RuntimeError(u'Using both tx= and confirm= at once does not make sense') + raise RuntimeError( + u'Using both tx= and confirm= at once does not make sense') elif confirm is not None: tx = confirm else: tx = False try: - return (self.pub_tr if tx else self.pub_na).publish(message, exchange, routing_key) + return (self.pub_tr if tx else self.pub_na).publish(message, + exchange, + routing_key) except Publisher.UnusablePublisher: - raise NotImplementedError(u'Sorry, this functionality is not yet implemented!') + raise NotImplementedError( + u'Sorry, this functionality is not yet implemented!') def start(self, wait=True): """ @@ -180,7 +188,8 @@ class Cluster(object): self.events = six.moves.queue.Queue() # for coolamqp.clustering.events.* - self.snr = SingleNodeReconnector(self.node, self.attache_group, self.listener) + self.snr = SingleNodeReconnector(self.node, self.attache_group, + self.listener) self.snr.on_fail.add(lambda: self.events.put_nowait(ConnectionLost())) if self.on_fail is not None: self.snr.on_fail.add(self.on_fail) diff --git a/coolamqp/uplink/connection/__init__.py b/coolamqp/uplink/connection/__init__.py index 8a07f01dcff33f918aa859559d29255aec4a4e9f..47cdf5eafbaa64c6704c8e9c53d02a4598f190cb 100644 --- a/coolamqp/uplink/connection/__init__.py +++ b/coolamqp/uplink/connection/__init__.py @@ -12,7 +12,7 @@ Connection is something that can: from __future__ import absolute_import, division, print_function from coolamqp.uplink.connection.connection import Connection -from coolamqp.uplink.connection.states import ST_OFFLINE, ST_CONNECTING, \ - ST_ONLINE from coolamqp.uplink.connection.watches import FailWatch, Watch, \ HeaderOrBodyWatch, MethodWatch, AnyWatch +from coolamqp.uplink.connection.states import ST_OFFLINE, ST_CONNECTING, \ + ST_ONLINE diff --git a/coolamqp/uplink/connection/connection.py b/coolamqp/uplink/connection/connection.py index 8c8e9266a16c1480e0bd3091e4d99c36233e2e59..182f2d827e957462c98a5ef7cdb0ab87d91f393d 100644 --- a/coolamqp/uplink/connection/connection.py +++ b/coolamqp/uplink/connection/connection.py @@ -12,7 +12,8 @@ from coolamqp.framing.frames import AMQPMethodFrame from coolamqp.uplink.handshake import Handshaker from coolamqp.framing.definitions import ConnectionClose, ConnectionCloseOk from coolamqp.uplink.connection.watches import MethodWatch, Watch -from coolamqp.uplink.connection.states import ST_ONLINE, ST_OFFLINE, ST_CONNECTING +from coolamqp.uplink.connection.states import ST_ONLINE, ST_OFFLINE, \ + ST_CONNECTING from coolamqp.objects import Callable logger = logging.getLogger(__name__) @@ -105,7 +106,8 @@ class Connection(object): while True: try: - sock.connect((self.node_definition.host, self.node_definition.port)) + sock.connect( + (self.node_definition.host, self.node_definition.port)) except socket.error as e: time.sleep(0.5) # Connection refused? Very bad things? else: @@ -120,7 +122,8 @@ class Connection(object): on_read=self.recvf.put, on_fail=self.on_fail) self.sendf = SendingFramer(self.listener_socket.send) - self.watch_for_method(0, (ConnectionClose, ConnectionCloseOk), self.on_connection_close) + self.watch_for_method(0, (ConnectionClose, ConnectionCloseOk), + self.on_connection_close) Handshaker(self, self.node_definition, self.on_connected) @@ -169,7 +172,8 @@ class Connection(object): if isinstance(payload, ConnectionClose): self.send([AMQPMethodFrame(0, ConnectionCloseOk())]) - logger.info(u'Broker closed our connection - code %s reason %s', payload.reply_code, + logger.info(u'Broker closed our connection - code %s reason %s', + payload.reply_code, payload.reply_text.tobytes().decode('utf8')) elif isinstance(payload, ConnectionCloseOk): @@ -233,7 +237,8 @@ class Connection(object): # print('watch',watch,'was cancelled') continue - if ((not watch_triggered) or (not watch.oneshot)) and (not watch.cancelled): + if ((not watch_triggered) or (not watch.oneshot)) and ( + not watch.cancelled): # Watch remains alive if it was NOT triggered, or it's NOT a oneshot alive_watches.append(watch) @@ -260,7 +265,8 @@ class Connection(object): # print('any watch', watch, 'was cancelled') continue - if ((not watch_triggered) or (not watch.oneshot)) and (not watch.cancelled): + if ((not watch_triggered) or (not watch.oneshot)) and ( + not watch.cancelled): # Watch remains alive if it was NOT triggered, or it's NOT a oneshot alive_watches.append(watch) @@ -315,7 +321,8 @@ class Connection(object): self.watch(mw) return mw - def method_and_watch(self, channel_id, method_payload, method_or_methods, callback): + def method_and_watch(self, channel_id, method_payload, method_or_methods, + callback): """ A syntactic sugar for diff --git a/docs/index.rst b/docs/index.rst index 3fdbdb2ea98cc4cb85404ad04ff5127cc146e789..55c87213879ea90ee040a9c965f75d6e9c6870c3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,11 +2,11 @@ Welcome to CoolAMQP's documentation! ==================================== .. toctree:: - :maxdepth: 2 - :caption: Contents: +:maxdepth: 2 + :caption: Contents: - tutorial - caveats + tutorial + caveats Indices and tables diff --git a/resources/amqp0-9-1.extended.xml b/resources/amqp0-9-1.extended.xml index 7ba2d60d3bab985e47c48fa25e2b219bcbac1786..f7aca67cdaba8b9765f8636a86d1445cb2f5c308 100644 --- a/resources/amqp0-9-1.extended.xml +++ b/resources/amqp0-9-1.extended.xml @@ -156,3192 +156,3849 @@ --> -<amqp major = "0" minor = "9" revision = "1" - port = "5672" comment = "AMQ Protocol version 0-9-1"> - <!-- +<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" /> + <!-- 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"/> - <response name = "tune-ok" /> + <!-- Protocol constants --> + <constant name="frame-min-size" value="4096"/> + <constant name="frame-end" value="206"/> - <field name = "channel-max" domain = "short" label = "proposed maximum channels"> + <!-- Reply codes --> + <constant name="reply-success" value="200"> <doc> - Specifies highest channel number that the server permits. Usable channel numbers - are in the range 1..channel-max. Zero indicates no specified limit. + 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> - </field> + </constant> - <field name = "frame-max" domain = "long" label = "proposed maximum frame size"> + <constant name="content-too-large" value="311" class="soft-error"> <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. + 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> - <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> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="no-consumers" value="313" class="soft-error"> <doc> - The delay, in seconds, of the connection heartbeat that the server wants. - Zero means the server does not want a heartbeat. + 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> - </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" /> + </constant> - <field name = "channel-max" domain = "short" label = "negotiated maximum channels"> + <constant name="connection-forced" value="320" class="hard-error"> <doc> - The maximum total number of channels that the client will use per connection. + An operator intervened to close the connection for some reason. The + client + may retry at some later date. </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> + </constant> - <field name = "frame-max" domain = "long" label = "negotiated maximum frame size"> + <constant name="invalid-path" value="402" class="hard-error"> <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. + The client tried to work with an unknown virtual host. </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> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="access-refused" value="403" class="soft-error"> <doc> - The delay, in seconds, of the connection heartbeat that the client wants. Zero - means the client does not want a heartbeat. + The client attempted to work with a server entity to which it has no + access due to security settings. </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" /> + </constant> - <field name = "virtual-host" domain = "path" label = "virtual host name"> + <constant name="not-found" value="404" class="soft-error"> <doc> - The name of the virtual host to work with. + The client attempted to work with a server entity that does not + exist. </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> + </constant> - <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"> + <constant name="resource-locked" value="405" class="soft-error"> <doc> - When the close is provoked by a method exception, this is the class of the - method. + The client attempted to work with a server entity to which it has no + access because another client is working with it. </doc> - </field> + </constant> - <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> - - <method name = "blocked" index = "60"> - <doc> - This method indicates that a connection has been blocked - and does not accept new publishes. - </doc> - <chassis name = "server" implement = "MUST"/> - <chassis name = "client" implement = "MUST"/> - <field name = "reason" domain = "shortstr" /> - </method> - <method name = "unblocked" index = "61"> - <doc> - This method indicates that a connection has been unblocked - and now accepts publishes. - </doc> - <chassis name = "server" implement = "MUST"/> - <chassis name = "client" 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"> + <constant name="precondition-failed" value="406" class="soft-error"> <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. + The client requested a method that was not allowed because some + precondition + failed. </doc> - </rule> + </constant> - <rule name = "bidirectional"> + <constant name="frame-error" value="501" class="hard-error"> <doc> - When sending content frames, a peer SHOULD monitor the channel for incoming - methods and respond to a Channel.Flow as rapidly as possible. + The sender sent a malformed frame that the recipient could not + decode. + This strongly implies a programming error in the sending peer. </doc> - </rule> + </constant> - <rule name = "throttling"> + <constant name="syntax-error" value="502" class="hard-error"> <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. + 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> - </rule> + </constant> - <rule name = "expected-behaviour"> + <constant name="command-invalid" value="503" class="hard-error"> <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. + 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> - </rule> + </constant> - <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"> + <constant name="channel-error" value="504" class="hard-error"> <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. + 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> - </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" /> + </constant> - <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"> + <constant name="unexpected-frame" value="505" class="hard-error"> <doc> - When the close is provoked by a method exception, this is the class of the - method. + 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> - </field> + </constant> - <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"> + <constant name="resource-error" value="506" class="hard-error"> <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 - / C:BIND S:BIND-OK - / C:UNBIND S:UNBIND-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. + 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> - </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> + </constant> - <field name = "passive" domain = "bit" label = "do not create exchange"> + <constant name="not-allowed" value="530" class="hard-error"> <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. + 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> - <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> + </constant> - <field name = "durable" domain = "bit" label = "request a durable exchange"> + <constant name="not-implemented" value="540" class="hard-error"> <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. + The client tried to use functionality that is not implemented in the + server. </doc> - <rule name = "support"> - <doc> - The server MUST support both durable and transient exchanges. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> + </constant> - <field name = "auto-delete" domain = "bit" label = "auto-delete when unused"> + <constant name="internal-error" value="541" class="hard-error"> <doc> - If set, the exchange is deleted when all queues have - finished using it. + 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> - <rule name = "amq_exchange_02"> - <doc> - The server SHOULD allow for a reasonable delay between the - point when it determines that an exchange is not being - used (or no longer used), and the point when it deletes - the exchange. At the least it must allow a client to - create an exchange and then bind a queue to it, with a - small but non-zero delay between these two actions. - </doc> - </rule> - <rule name = "amq_exchange_25"> - <doc> - The server MUST ignore the auto-delete field if the - exchange already exists. - </doc> - </rule> - </field> + </constant> - <field name = "internal" domain = "bit" label = "create internal exchange"> - <doc> - If set, the exchange may not be used directly by publishers, - but only when bound to other exchanges. Internal exchanges - are used to construct wiring that is not visible to - applications. - </doc> - </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 = "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> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name = "bind" synchronous = "1" index = "30" - label = "bind exchange to an exchange"> - - <doc>This method binds an exchange to an exchange.</doc> - - <rule name = "duplicates"> - <doc> - A server MUST allow and ignore duplicate bindings - that is, - two or more bind methods for a specific exchanges, with - identical arguments - without treating these as an error. - </doc> - <doc type = "scenario"> - A client binds an exchange to an exchange. The client then - repeats the bind (with identical arguments). - </doc> - </rule> - - <rule name = "cyclical"> - <doc> - A server MUST allow cycles of exchange bindings to be - created including allowing an exchange to be bound to - itself. - </doc> - <doc type = "scenario"> - A client declares an exchange and binds it to itself. - </doc> - </rule> - - <rule name = "unique"> - <doc> - A server MUST not deliver the same message more than once to - a destination exchange, even if the topology of exchanges - and bindings results in multiple (even infinite) routes to - that exchange. - </doc> - <doc type = "scenario"> - A client declares an exchange and binds it using multiple - bindings to the amq.topic exchange. The client then - publishes a message to the amq.topic exchange that matches - all the bindings. - </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 = "destination" domain = "exchange-name" - label = "name of the destination exchange to bind to"> - <doc>Specifies the name of the destination exchange to bind.</doc> - <rule name = "exchange-existence" on-failure = "not-found"> - <doc> - A client MUST NOT be allowed to bind a non-existent - destination exchange. - </doc> - <doc type = "scenario"> - A client attempts to bind an undeclared exchange to an - 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 an exchange and binds a blank exchange - name to it. - </doc> - </rule> - </field> - - <field name = "source" domain = "exchange-name" - label = "name of the source exchange to bind to"> - <doc>Specifies the name of the source exchange to bind.</doc> - <rule name = "exchange-existence" on-failure = "not-found"> - <doc> - A client MUST NOT be allowed to bind a non-existent source - exchange. - </doc> - <doc type = "scenario"> - A client attempts to bind an exchange to an 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 an exchange 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. - </doc> - </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="31" - 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 = "40" - label = "unbind an exchange from an exchange"> - <doc>This method unbinds an exchange 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 = "destination" domain = "exchange-name"> - <doc>Specifies the name of the destination exchange to unbind.</doc> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind an exchange that - does not exist from an exchange. - </doc> - <doc type = "scenario"> - The client attempts to unbind a non-existent exchange from - an 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 an exchange, binds a blank exchange - name to it, and then unbinds a blank exchange name from - it. - </doc> - </rule> - </field> - - <field name = "source" domain = "exchange-name"> - <doc>Specifies the name of the source exchange to unbind.</doc> - <rule name = "must-exist" on-failure = "not-found"> - <doc> - The client MUST NOT attempt to unbind an exchange from an - exchange that does not exist. - </doc> - <doc type = "scenario"> - The client attempts to unbind an exchange 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 an exchange, binds an exchange to a - blank exchange name, and then unbinds an exchange from a - black 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 = "no-wait" domain = "no-wait"/> - - <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> - - </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> + <!-- + ====================================================== + == DOMAIN TYPES + ====================================================== + --> - <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> + <domain name="class-id" type="short"/> - <rule name = "durable-exchange"> + <domain name="consumer-tag" type="shortstr" label="consumer tag"> <doc> - Bindings of durable queues to durable exchanges are automatically durable - and the server MUST restore such bindings after a server restart. + Identifier for the consumer, valid within the current channel. </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> + </domain> - <rule name = "binding-count"> + <domain name="delivery-tag" type="longlong" + label="server-assigned delivery tag"> <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. + The server-assigned and channel-specific delivery tag </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 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 = "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 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> - </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> + </domain> - <field name = "routing-key" domain = "shortstr" label = "message routing key"> + <domain name="exchange-name" type="shortstr" label="exchange name"> <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. + The exchange name is a client-selected string that identifies the + exchange for + publish methods. </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> + <assert check="length" value="127"/> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </domain> - <field name = "no-wait" domain = "no-wait" /> + <domain name="method-id" type="short"/> - <field name = "arguments" domain = "table" label = "arguments for binding"> + <domain name="no-ack" type="bit" label="no acknowledgement needed"> <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> + 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> - <rule name = "02"> + <domain name="no-local" type="bit" label="do not deliver own messages"> <doc> - The server MUST NOT purge messages that have already been sent to a client - but not yet acknowledged. + If the no-local field is set the server will not send messages to + the connection that + published them. </doc> - </rule> + </domain> - <rule name = "03"> + <domain name="no-wait" type="bit" label="do not send reply method"> <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. + 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> - </rule> + </domain> - <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"> + <domain name="path" type="shortstr"> <doc> - Reports the number of messages purged. + Unconstrained. </doc> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <assert check="notnull"/> + <assert check="length" value="127"/> + </domain> - <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"> + <domain name="peer-properties" type="table"> <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. + This table provides a set of peer properties, used for + identification, debugging, + and general information. </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - - <response name = "delete-ok" /> + </domain> - <!-- 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"> + <domain name="queue-name" type="shortstr" label="queue name"> <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 - / S:ACK - / C:REJECT - / C:NACK - / S:NACK - / 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 + 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> + + <method name="blocked" index="60"> + <doc> + This method indicates that a connection has been blocked + and does not accept new publishes. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + <field name="reason" domain="shortstr"/> + </method> + <method name="unblocked" index="61"> + <doc> + This method indicates that a connection has been unblocked + and now accepts publishes. + </doc> + <chassis name="server" implement="MUST"/> + <chassis name="client" 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 + / C:BIND S:BIND-OK + / C:UNBIND S:UNBIND-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> + + <field name="auto-delete" domain="bit" + label="auto-delete when unused"> + <doc> + If set, the exchange is deleted when all queues have + finished using it. + </doc> + <rule name="amq_exchange_02"> + <doc> + The server SHOULD allow for a reasonable delay between + the + point when it determines that an exchange is not being + used (or no longer used), and the point when it deletes + the exchange. At the least it must allow a client to + create an exchange and then bind a queue to it, with a + small but non-zero delay between these two actions. + </doc> + </rule> + <rule name="amq_exchange_25"> + <doc> + The server MUST ignore the auto-delete field if the + exchange already exists. + </doc> + </rule> + </field> + + <field name="internal" domain="bit" + label="create internal exchange"> + <doc> + If set, the exchange may not be used directly by publishers, + but only when bound to other exchanges. Internal exchanges + are used to construct wiring that is not visible to + applications. + </doc> + </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="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> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="bind" synchronous="1" index="30" + label="bind exchange to an exchange"> + + <doc>This method binds an exchange to an exchange.</doc> + + <rule name="duplicates"> + <doc> + A server MUST allow and ignore duplicate bindings - that is, + two or more bind methods for a specific exchanges, with + identical arguments - without treating these as an error. + </doc> + <doc type="scenario"> + A client binds an exchange to an exchange. The client then + repeats the bind (with identical arguments). + </doc> + </rule> + + <rule name="cyclical"> + <doc> + A server MUST allow cycles of exchange bindings to be + created including allowing an exchange to be bound to + itself. + </doc> + <doc type="scenario"> + A client declares an exchange and binds it to itself. + </doc> + </rule> + + <rule name="unique"> + <doc> + A server MUST not deliver the same message more than once to + a destination exchange, even if the topology of exchanges + and bindings results in multiple (even infinite) routes to + that exchange. + </doc> + <doc type="scenario"> + A client declares an exchange and binds it using multiple + bindings to the amq.topic exchange. The client then + publishes a message to the amq.topic exchange that matches + all the bindings. + </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="destination" domain="exchange-name" + label="name of the destination exchange to bind to"> + <doc>Specifies the name of the destination exchange to bind. + </doc> + <rule name="exchange-existence" on-failure="not-found"> + <doc> + A client MUST NOT be allowed to bind a non-existent + destination exchange. + </doc> + <doc type="scenario"> + A client attempts to bind an undeclared exchange to an + 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 an exchange and binds a blank + exchange + name to it. + </doc> + </rule> + </field> + + <field name="source" domain="exchange-name" + label="name of the source exchange to bind to"> + <doc>Specifies the name of the source exchange to bind.</doc> + <rule name="exchange-existence" on-failure="not-found"> + <doc> + A client MUST NOT be allowed to bind a non-existent + source + exchange. + </doc> + <doc type="scenario"> + A client attempts to bind an exchange to an 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 an exchange 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. + </doc> + </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="31" + 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="40" + label="unbind an exchange from an exchange"> + <doc>This method unbinds an exchange 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="destination" domain="exchange-name"> + <doc>Specifies the name of the destination exchange to unbind. + </doc> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind an exchange that + does not exist from an exchange. + </doc> + <doc type="scenario"> + The client attempts to unbind a non-existent exchange + from + an 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 an exchange, binds a blank exchange + name to it, and then unbinds a blank exchange name from + it. + </doc> + </rule> + </field> + + <field name="source" domain="exchange-name"> + <doc>Specifies the name of the source exchange to unbind.</doc> + <rule name="must-exist" on-failure="not-found"> + <doc> + The client MUST NOT attempt to unbind an exchange from + an + exchange that does not exist. + </doc> + <doc type="scenario"> + The client attempts to unbind an exchange 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 an exchange, binds an exchange to a + blank exchange name, and then unbinds an exchange from a + black 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="no-wait" domain="no-wait"/> + + <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> + + </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 + / S:ACK + / C:REJECT + / C:NACK + / S:NACK + / 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> - RabbitMQ has reinterpreted this field. The original - specification said: "By default the QoS settings apply to - the current channel only. If this field is set, they are - applied to the entire connection." Instead, RabbitMQ takes - global=false to mean that the QoS settings should apply - per-consumer (for new consumers on the channel; existing - ones being unaffected) and global=true to mean that the QoS - settings should apply per-channel. - </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. - - It may also be sent from the server to the client in the event - of the consumer being unexpectedly cancelled (i.e. cancelled - for any reason other than the server receiving the - corresponding basic.cancel from the client). This allows - clients to be notified of the loss of consumers due to events - such as queue deletion. Note that as it is not a MUST for - clients to accept this method from the server, it is advisable - for the broker to be able to identify those clients that are - capable of accepting the method, through some means of - capability negotiation. - </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" /> - <chassis name = "client" implement = "SHOULD" /> - <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" /> - <chassis name = "server" implement = "MAY" /> - <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> - When sent by the client, this method acknowledges one or more - messages delivered via the Deliver or Get-Ok methods. - - When sent by server, this method acknowledges one or more - messages published with the Publish method on a channel in - confirm mode. - - The acknowledgement can be for a single message or a set of - messages up to and including a specific message. - </doc> - - <chassis name = "server" implement = "MUST" /> - <chassis name ="client" 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 multiple messages can be acknowledged - 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, this indicates acknowledgement of - all outstanding messages. - </doc> - <rule name = "exists" on-failure = "precondition-failed"> - <doc> - A message MUST not be acknowledged more than once. The - receiving peer 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. - </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> - - <method name = "nack" index = "120" label = "reject one or more incoming messages"> - <doc> - This method allows a client to reject one or more incoming messages. It can be - used to interrupt and cancel large incoming messages, or return untreatable - messages to their original queue. - - This method is also used by the server to inform publishers on channels in - confirm mode of unhandled messages. If a publisher receives this method, it - probably needs to republish the offending messages. - </doc> - - <rule name = "01"> - <doc> - The server SHOULD be capable of accepting and processing the Nack 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> - - <rule name = "04"> - <doc> - A client publishing messages to a channel in confirm mode SHOULD be capable of accepting - and somehow handling the Nack method. - </doc> - <doc type = "scenario"> - TODO - </doc> - </rule> - - <chassis name = "server" implement = "MUST" /> - <chassis name = "client" implement = "MUST" /> - - <field name = "delivery-tag" domain = "delivery-tag" /> - - <field name = "multiple" domain = "bit" label = "reject multiple messages"> - <doc> - If set to 1, the delivery tag is treated as "up to and - including", so that multiple messages can be rejected - 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, this indicates rejection of - all outstanding messages. - </doc> - <rule name = "exists" on-failure = "precondition-failed"> - <doc> - A message MUST not be rejected more than once. The - receiving peer MUST validate that a non-zero delivery-tag - refers to an unacknowledged, delivered message, and - raise a channel exception if this is not the case. - </doc> - <doc type = "scenario"> - TODO. - </doc> - </rule> - </field> - - <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. - Clients receiving the Nack methods should ignore this flag. - </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> - - </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> - - <!-- == CONFIRM ========================================================== --> - - <class name = "confirm" handler = "channel" index = "85" label = "work with confirms"> - <doc> - The Confirm class allows publishers to put the channel in - confirm mode and subsequently be notified when messages have been - handled by the broker. The intention is that all messages - published on a channel in confirm mode will be acknowledged at - some point. By acknowledging a message the broker assumes - responsibility for it and indicates that it has done something - it deems reasonable with it. - - Unroutable mandatory or immediate messages are acknowledged - right after the Basic.Return method. Messages are acknowledged - when all queues to which the message has been routed - have either delivered the message and received an - acknowledgement (if required), or enqueued the message (and - persisted it if required). - - Published messages are assigned ascending sequence numbers, - starting at 1 with the first Confirm.Select method. The server - confirms messages by sending Basic.Ack methods referring to these - sequence numbers. - </doc> - - <rule name = "all messages acknowledged"> - <doc> - The server MUST acknowledge all messages received after the - channel was put into confirm mode. - </doc> - </rule> - - <rule name = "all queues"> - <doc> - The server MUST acknowledge a message only after it was - properly handled by all the queues it was delivered to. - </doc> - </rule> - - <rule name = "unroutable messages"> - <doc> - The server MUST acknowledge an unroutable mandatory or - immediate message only after it sends the Basic.Return. - </doc> - </rule> - - <rule name = "time guarantees"> - <doc> - No guarantees are made as to how soon a message is - acknowledged. Applications SHOULD NOT make assumptions about - this. - </doc> - </rule> - - <doc type = "grammar"> - confirm = C:SELECT S:SELECT-OK - </doc> - - <chassis name = "server" implement = "SHOULD" /> - <chassis name = "client" implement = "MAY" /> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - <method name="select" synchronous="1" index="10"> - select confirm mode (i.e. enable publisher acknowledgements) - <doc> - This method sets the channel to use publisher acknowledgements. - The client can only use this method on a non-transactional - channel. - </doc> - <chassis name="server" implement="MUST"/> - <response name="select-ok"/> - <field name = "nowait" type = "bit"> - do not send a 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> - </field> - </method> - - <method name="select-ok" synchronous="1" index="11"> - acknowledge confirm mode - <doc> - This method confirms to the client that the channel was successfully - set to use publisher acknowledgements. - </doc> - <chassis name="client" implement="MUST"/> - </method> - </class> + <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> + RabbitMQ has reinterpreted this field. The original + specification said: "By default the QoS settings apply to + the current channel only. If this field is set, they are + applied to the entire connection." Instead, RabbitMQ takes + global=false to mean that the QoS settings should apply + per-consumer (for new consumers on the channel; existing + ones being unaffected) and global=true to mean that the QoS + settings should apply per-channel. + </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. + + It may also be sent from the server to the client in the event + of the consumer being unexpectedly cancelled (i.e. cancelled + for any reason other than the server receiving the + corresponding basic.cancel from the client). This allows + clients to be notified of the loss of consumers due to events + such as queue deletion. Note that as it is not a MUST for + clients to accept this method from the server, it is advisable + for the broker to be able to identify those clients that are + capable of accepting the method, through some means of + capability negotiation. + </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"/> + <chassis name="client" implement="SHOULD"/> + <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"/> + <chassis name="server" implement="MAY"/> + <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> + When sent by the client, this method acknowledges one or more + messages delivered via the Deliver or Get-Ok methods. + + When sent by server, this method acknowledges one or more + messages published with the Publish method on a channel in + confirm mode. + + The acknowledgement can be for a single message or a set of + messages up to and including a specific message. + </doc> + + <chassis name="server" implement="MUST"/> + <chassis name="client" 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 multiple messages can be acknowledged + 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, this indicates acknowledgement of + all outstanding messages. + </doc> + <rule name="exists" on-failure="precondition-failed"> + <doc> + A message MUST not be acknowledged more than once. The + receiving peer 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. + </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> + + <method name="nack" index="120" + label="reject one or more incoming messages"> + <doc> + This method allows a client to reject one or more incoming + messages. It can be + used to interrupt and cancel large incoming messages, or return + untreatable + messages to their original queue. + + This method is also used by the server to inform publishers on + channels in + confirm mode of unhandled messages. If a publisher receives this + method, it + probably needs to republish the offending messages. + </doc> + + <rule name="01"> + <doc> + The server SHOULD be capable of accepting and processing the + Nack 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> + + <rule name="04"> + <doc> + A client publishing messages to a channel in confirm mode + SHOULD be capable of accepting + and somehow handling the Nack method. + </doc> + <doc type="scenario"> + TODO + </doc> + </rule> + + <chassis name="server" implement="MUST"/> + <chassis name="client" implement="MUST"/> + + <field name="delivery-tag" domain="delivery-tag"/> + + <field name="multiple" domain="bit" + label="reject multiple messages"> + <doc> + If set to 1, the delivery tag is treated as "up to and + including", so that multiple messages can be rejected + 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, this indicates rejection of + all outstanding messages. + </doc> + <rule name="exists" on-failure="precondition-failed"> + <doc> + A message MUST not be rejected more than once. The + receiving peer MUST validate that a non-zero + delivery-tag + refers to an unacknowledged, delivered message, and + raise a channel exception if this is not the case. + </doc> + <doc type="scenario"> + TODO. + </doc> + </rule> + </field> + + <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. + Clients receiving the Nack methods should ignore this flag. + </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> + + </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> + + <!-- == CONFIRM ========================================================== --> + + <class name="confirm" handler="channel" index="85" + label="work with confirms"> + <doc> + The Confirm class allows publishers to put the channel in + confirm mode and subsequently be notified when messages have been + handled by the broker. The intention is that all messages + published on a channel in confirm mode will be acknowledged at + some point. By acknowledging a message the broker assumes + responsibility for it and indicates that it has done something + it deems reasonable with it. + + Unroutable mandatory or immediate messages are acknowledged + right after the Basic.Return method. Messages are acknowledged + when all queues to which the message has been routed + have either delivered the message and received an + acknowledgement (if required), or enqueued the message (and + persisted it if required). + + Published messages are assigned ascending sequence numbers, + starting at 1 with the first Confirm.Select method. The server + confirms messages by sending Basic.Ack methods referring to these + sequence numbers. + </doc> + + <rule name="all messages acknowledged"> + <doc> + The server MUST acknowledge all messages received after the + channel was put into confirm mode. + </doc> + </rule> + + <rule name="all queues"> + <doc> + The server MUST acknowledge a message only after it was + properly handled by all the queues it was delivered to. + </doc> + </rule> + + <rule name="unroutable messages"> + <doc> + The server MUST acknowledge an unroutable mandatory or + immediate message only after it sends the Basic.Return. + </doc> + </rule> + + <rule name="time guarantees"> + <doc> + No guarantees are made as to how soon a message is + acknowledged. Applications SHOULD NOT make assumptions about + this. + </doc> + </rule> + + <doc type="grammar"> + confirm = C:SELECT S:SELECT-OK + </doc> + + <chassis name="server" implement="SHOULD"/> + <chassis name="client" implement="MAY"/> + + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <method name="select" synchronous="1" index="10"> + select confirm mode (i.e. enable publisher acknowledgements) + <doc> + This method sets the channel to use publisher acknowledgements. + The client can only use this method on a non-transactional + channel. + </doc> + <chassis name="server" implement="MUST"/> + <response name="select-ok"/> + <field name="nowait" type="bit"> + do not send a 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> + </field> + </method> + + <method name="select-ok" synchronous="1" index="11"> + acknowledge confirm mode + <doc> + This method confirms to the client that the channel was + successfully + set to use publisher acknowledgements. + </doc> + <chassis name="client" implement="MUST"/> + </method> + </class> </amqp> diff --git a/resources/amqp0-9-1.xml b/resources/amqp0-9-1.xml index da785eb3bed370d7c11852fce8ef7fe7f366f2f6..2d56a5eb8d7aa5e3846f62929c8668430ecef71e 100644 --- a/resources/amqp0-9-1.xml +++ b/resources/amqp0-9-1.xml @@ -140,2704 +140,3335 @@ --> -<amqp major = "0" minor = "9" revision = "1" - port = "5672" comment = "AMQ Protocol version 0-9-1"> - <!-- +<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> + <!-- 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"/> - <chassis name = "client" implement = "MUST" /> - <response name = "start-ok" /> + <!-- Protocol constants --> + <constant name="frame-min-size" value="4096"/> + <constant name="frame-end" value="206"/> - <field name = "version-major" domain = "octet" label = "protocol major version"> + <!-- Reply codes --> + <constant name="reply-success" value="200"> <doc> - The major version number can take any value from 0 to 99 as defined in the - AMQP specification. + 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> - </field> + </constant> - <field name = "version-minor" domain = "octet" label = "protocol minor version"> + <constant name="content-too-large" value="311" class="soft-error"> <doc> - The minor version number can take any value from 0 to 99 as defined in the - AMQP specification. + 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> - </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> + </constant> - <field name = "mechanisms" domain = "longstr" label = "available security mechanisms"> + <constant name="no-consumers" value="313" class="soft-error"> <doc> - A list of the security mechanisms that the server supports, delimited by spaces. + 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> - <assert check = "notnull" /> - </field> + </constant> - <field name = "locales" domain = "longstr" label = "available message locales"> + <constant name="connection-forced" value="320" class="hard-error"> <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. + An operator intervened to close the connection for some reason. The + client + may retry at some later date. </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> + </constant> - <field name = "mechanism" domain = "shortstr" label = "selected security mechanism"> + <constant name="invalid-path" value="402" class="hard-error"> <doc> - A single security mechanisms selected by the client, which must be one of those - specified by the server. + The client tried to work with an unknown virtual host. </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> + </constant> - <field name = "response" domain = "longstr" label = "security response data"> + <constant name="access-refused" value="403" class="soft-error"> <doc> - A block of opaque data passed to the security mechanism. The contents of this - data are defined by the SASL security mechanism. + The client attempted to work with a server entity to which it has no + access due to security settings. </doc> - <assert check = "notnull" /> - </field> + </constant> - <field name = "locale" domain = "shortstr" label = "selected message locale"> + <constant name="not-found" value="404" class="soft-error"> <doc> - A single message locale selected by the client, which must be one of those - specified by the server. + The client attempted to work with a server entity that does not + exist. </doc> - <assert check = "notnull" /> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + </constant> - <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"> + <constant name="resource-locked" value="405" class="soft-error"> <doc> - Challenge information, a block of opaque binary data passed to the security - mechanism. + The client attempted to work with a server entity to which it has no + access because another client is working with it. </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> + </constant> - <chassis name = "server" implement = "MUST" /> - - <field name = "response" domain = "longstr" label = "security response data"> + <constant name="precondition-failed" value="406" class="soft-error"> <doc> - A block of opaque data passed to the security mechanism. The contents of this - data are defined by the SASL security mechanism. + The client requested a method that was not allowed because some + precondition + failed. </doc> - <assert check = "notnull" /> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + </constant> - <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"> + <constant name="frame-error" value="501" class="hard-error"> <doc> - Specifies highest channel number that the server permits. Usable channel numbers - are in the range 1..channel-max. Zero indicates no specified limit. + The sender sent a malformed frame that the recipient could not + decode. + This strongly implies a programming error in the sending peer. </doc> - </field> + </constant> - <field name = "frame-max" domain = "long" label = "proposed maximum frame size"> + <constant name="syntax-error" value="502" class="hard-error"> <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. + 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> - <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> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="command-invalid" value="503" class="hard-error"> <doc> - The delay, in seconds, of the connection heartbeat that the server wants. - Zero means the server does not want a heartbeat. + 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> - </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> + </constant> - <chassis name = "server" implement = "MUST" /> - - <field name = "channel-max" domain = "short" label = "negotiated maximum channels"> + <constant name="channel-error" value="504" class="hard-error"> <doc> - The maximum total number of channels that the client will use per connection. + 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> - <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> + </constant> - <field name = "frame-max" domain = "long" label = "negotiated maximum frame size"> + <constant name="unexpected-frame" value="505" class="hard-error"> <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. + 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> - <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> + </constant> - <field name = "heartbeat" domain = "short" label = "desired heartbeat delay"> + <constant name="resource-error" value="506" class="hard-error"> <doc> - The delay, in seconds, of the connection heartbeat that the client wants. Zero - means the client does not want a heartbeat. + 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> - </field> - </method> - - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + </constant> - <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"> + <constant name="not-allowed" value="530" class="hard-error"> <doc> - The name of the virtual host to work with. + 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> - <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> + </constant> - <rule name = "throttling"> + <constant name="not-implemented" value="540" class="hard-error"> <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. + The client tried to use functionality that is not implemented in the + server. </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" /> + </constant> - <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"> + <constant name="internal-error" value="541" class="hard-error"> <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. + 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> - </rule> + </constant> - <chassis name = "client" implement = "MUST" /> - <chassis name = "server" implement = "MUST" /> - <response name = "close-ok" /> + <!-- + ====================================================== + == DOMAIN TYPES + ====================================================== + --> - <field name = "reply-code" domain = "reply-code" /> - <field name = "reply-text" domain = "reply-text" /> + <domain name="class-id" type="short"/> - <field name = "class-id" domain = "class-id" label = "failing method class"> + <domain name="consumer-tag" type="shortstr" label="consumer tag"> <doc> - When the close is provoked by a method exception, this is the class of the - method. + Identifier for the consumer, valid within the current channel. </doc> - </field> + </domain> - <field name = "method-id" domain = "method-id" label = "failing method ID"> + <domain name="delivery-tag" type="longlong" + label="server-assigned delivery tag"> <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. + The server-assigned and channel-specific delivery tag </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 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 = "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 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> - <assert check = "notnull" /> - </field> + </domain> - <field name = "type" domain = "shortstr" label = "exchange type"> + <domain name="exchange-name" type="shortstr" label="exchange name"> <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. + The exchange name is a client-selected string that identifies the + exchange for + publish methods. </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> + <assert check="length" value="127"/> + <assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/> + </domain> - <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> + <domain name="method-id" type="short"/> - <field name = "durable" domain = "bit" label = "request a durable exchange"> + <domain name="no-ack" type="bit" label="no acknowledgement needed"> <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. + 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> - <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" /> + </domain> - <field name = "arguments" domain = "table" label = "arguments for declaration"> + <domain name="no-local" type="bit" label="do not deliver own messages"> <doc> - A set of arguments for the declaration. The syntax and semantics of these - arguments depends on the server implementation. + If the no-local field is set the server will not send messages to + the connection that + published them. </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> + </domain> - <field name = "if-unused" domain = "bit" label = "delete only if unused"> + <domain name="no-wait" type="bit" label="do not send reply method"> <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. + 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> - <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> + </domain> - <rule name = "minimum-queues"> + <domain name="path" type="shortstr"> <doc> - The server SHOULD support a minimum of 256 queues per virtual host and ideally, - impose no limit except as defined by available resources. + Unconstrained. </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> + <assert check="notnull"/> + <assert check="length" value="127"/> + </domain> - <field name = "passive" domain = "bit" label = "do not create queue"> + <domain name="peer-properties" type="table"> <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. + This table provides a set of peer properties, used for + identification, debugging, + and general information. </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> + </domain> - <field name = "durable" domain = "bit" label = "request a durable queue"> + <domain name="queue-name" type="shortstr" label="queue name"> <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. + 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> - <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"> + <domain name="redelivered" type="bit" label="message is being redelivered"> <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. + This indicates that the message has been previously delivered to + this or + another client. </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 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 = "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 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> - </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> + </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> - </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 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 = "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 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> - </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 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-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 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> - </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 name="extensions"> + <doc> + The server MAY implement other exchange types as wanted. + </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> + <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + + <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> - </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 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> - </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 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> - </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 name="04"> + <doc> + The server MAY overflow non-persistent basic messages to + persistent + storage. + </doc> + <!-- Test scenario: untestable --> </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 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> - </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 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> - </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 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> - </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 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> - </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 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 = "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 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> - </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> + <!-- 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> - </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 name="not immediate"> + <doc> + Applications MUST NOT rely on the behaviour of transactions that + include messages published with the immediate option. + </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 name="not mandatory"> + <doc> + Applications MUST NOT rely on the behaviour of transactions that + include messages published with the mandatory option. + </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> + <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/setup.cfg b/setup.cfg index be77f9a4977a5d19c733738ad8992edbff218e8d..67cef602512486973824bb66b08eb6f628dacb9b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ [metadata] description-file = README.md name = CoolAMQP -version = 0.92 +version = 0.93a1 license = MIT License classifiers = Programming Language :: Python diff --git a/tests/run.py b/tests/run.py index e574f3cff37721b4c3b6f73748aaf7b738bc28e3..8a9f1a004294088672771881725738d84092b5a0 100644 --- a/tests/run.py +++ b/tests/run.py @@ -1,23 +1,22 @@ # coding=UTF-8 from __future__ import absolute_import, division, print_function import time, logging, threading -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + Exchange from coolamqp.exceptions import AMQPError from coolamqp.clustering import Cluster import time - NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) logging.basicConfig(level=logging.DEBUG) amqp = Cluster([NODE]) amqp.start(wait=True) - q = Queue(u'lolwut', auto_delete=True, exclusive=True) -c,f=amqp.consume(q, no_ack=True, body_receive_mode=1) +c, f = amqp.consume(q, no_ack=True, body_receive_mode=1) -#time.sleep(30) +# time.sleep(30) -#amqp.shutdown(True) +# amqp.shutdown(True) diff --git a/tests/test_clustering/__init__.py b/tests/test_clustering/__init__.py index 1c762b12fd99adc2f7d4e5137c5b872079457510..db0a0a6db68923bea6cabb6a4005abf5fdb90ffb 100644 --- a/tests/test_clustering/__init__.py +++ b/tests/test_clustering/__init__.py @@ -4,5 +4,3 @@ import six import logging logger = logging.getLogger(__name__) - - diff --git a/tests/test_clustering/test_a.py b/tests/test_clustering/test_a.py index 48c5e0dcb932f95b3317119ba028387da5e2806a..2f4fd62a40f247628f70fff5fc21bd6ce83fd029 100644 --- a/tests/test_clustering/test_a.py +++ b/tests/test_clustering/test_a.py @@ -7,7 +7,8 @@ import six import os import unittest import time, logging, threading, monotonic -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage, Exchange from coolamqp.clustering import Cluster, MessageReceived, NothingMuch import time @@ -17,7 +18,6 @@ logging.basicConfig(level=logging.DEBUG) class TestA(unittest.TestCase): - def setUp(self): self.c = Cluster([NODE]) self.c.start() @@ -38,14 +38,15 @@ class TestA(unittest.TestCase): con, fut = self.c.consume(Queue(u'hello', exclusive=True)) fut.result() - data = six.binary_type(os.urandom(20*1024*1024+1423)) + data = six.binary_type(os.urandom(20 * 1024 * 1024 + 1423)) - self.c.publish(Message(data), routing_key=b'hello', confirm=True).result() + self.c.publish(Message(data), routing_key=b'hello', + confirm=True).result() -# rmsg = self.c.drain(3) -# rmsg.ack() + # rmsg = self.c.drain(3) + # rmsg.ack() -# self.assertEquals(rmsg.body, data) + # self.assertEquals(rmsg.body, data) def test_actually_waits(self): a = monotonic.monotonic() @@ -54,7 +55,6 @@ class TestA(unittest.TestCase): self.assertTrue(monotonic.monotonic() - a >= 4) - def test_set_qos_but_later(self): con, fut = self.c.consume(Queue(u'hello', exclusive=True)) @@ -68,23 +68,23 @@ class TestA(unittest.TestCase): time.sleep(1) self.assertEquals(con.qos, (0, 110)) - def test_anonymq(self): - q = Queue(exchange=Exchange(u'ooo', type=b'fanout', auto_delete=True), auto_delete=True) + q = Queue(exchange=Exchange(u'ooo', type=b'fanout', auto_delete=True), + auto_delete=True) c, f = self.c.consume(q) f.result() def test_send_recv_zerolen(self): - P = {'q': False} def ok(e): self.assertIsInstance(e, ReceivedMessage) P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b''), routing_key=u'hello', tx=True).result() @@ -93,46 +93,48 @@ class TestA(unittest.TestCase): self.assertTrue(P['q']) def test_message_with_propos_confirm(self): - P = {'q': False} def ok(e): self.assertIsInstance(e, ReceivedMessage) self.assertEquals(e.body, b'hello') - #bcoz u can compare memoryviews to their providers :D + # bcoz u can compare memoryviews to their providers :D self.assertEquals(e.properties.content_type, b'text/plain') self.assertEquals(e.properties.content_encoding, b'utf8') P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b'hello', properties={ 'content_type': b'text/plain', 'content_encoding': b'utf8' }), routing_key=u'hello', confirm=True).result() - self.assertRaises(RuntimeError, lambda: self.c.publish(Message(b'hello', properties={ - 'content_type': b'text/plain', - 'content_encoding': b'utf8' - }), routing_key=u'hello', confirm=True, tx=True).result()) + self.assertRaises(RuntimeError, + lambda: self.c.publish(Message(b'hello', properties={ + 'content_type': b'text/plain', + 'content_encoding': b'utf8' + }), routing_key=u'hello', confirm=True, + tx=True).result()) time.sleep(1) self.assertTrue(P['q']) def test_message_with_propos(self): - P = {'q': False} def ok(e): self.assertIsInstance(e, ReceivedMessage) self.assertEquals(e.body, b'hello') - #bcoz u can compare memoryviews to their providers :D + # bcoz u can compare memoryviews to their providers :D self.assertEquals(e.properties.content_type, b'text/plain') self.assertEquals(e.properties.content_encoding, b'utf8') P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b'hello', properties={ 'content_type': b'text/plain', @@ -143,7 +145,6 @@ class TestA(unittest.TestCase): self.assertTrue(P['q']) - def test_send_recv_nonzerolen(self): """with callback function""" @@ -154,9 +155,11 @@ class TestA(unittest.TestCase): self.assertEquals(e.body, b'hello') P['q'] = True - con, fut = self.c.consume(Queue(u'hello', exclusive=True), on_message=ok, no_ack=True) + con, fut = self.c.consume(Queue(u'hello', exclusive=True), + on_message=ok, no_ack=True) fut.result() - self.c.publish(Message(b'hello'), routing_key=u'hello', tx=True).result() + self.c.publish(Message(b'hello'), routing_key=u'hello', + tx=True).result() time.sleep(1) @@ -208,12 +211,14 @@ class TestA(unittest.TestCase): self.assertEquals(b''.join(x.tobytes() for x in m.body), data) def test_consumer_cancel(self): - con, fut = self.c.consume(Queue(u'hello', exclusive=True, auto_delete=True)) + con, fut = self.c.consume( + Queue(u'hello', exclusive=True, auto_delete=True)) fut.result() con.cancel().result() def test_drain_1(self): - con, fut = self.c.consume(Queue(u'hello', exclusive=True, auto_delete=True)) + con, fut = self.c.consume( + Queue(u'hello', exclusive=True, auto_delete=True)) fut.result() self.c.publish(Message(b'ioi'), routing_key=u'hello') diff --git a/tests/test_clustering/test_double.py b/tests/test_clustering/test_double.py index ca6cbefdbf509dd612c33104ea0fdbbce9642eb8..c6ae6beaf8c9d5886fef2c2969b8a03365a86b1a 100644 --- a/tests/test_clustering/test_double.py +++ b/tests/test_clustering/test_double.py @@ -6,17 +6,17 @@ from __future__ import print_function, absolute_import, division import six import unittest import time, logging, threading -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage from coolamqp.clustering import Cluster + NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) from coolamqp.exceptions import AMQPError, RESOURCE_LOCKED - logging.basicConfig(level=logging.DEBUG) class TestDouble(unittest.TestCase): - def setUp(self): self.c1 = Cluster([NODE]) self.c1.start() @@ -28,7 +28,8 @@ class TestDouble(unittest.TestCase): self.c1.shutdown() self.c2.shutdown() - @unittest.skip("Since RabbitMQ does not support queue deletion, you need to do this manually") + @unittest.skip( + "Since RabbitMQ does not support queue deletion, you need to do this manually") def test_ccn(self): """ Will consumer cancel itself after Consumer Cancel Notification? @@ -44,7 +45,7 @@ class TestDouble(unittest.TestCase): con1, fut1 = self.c1.consume(q1) fut1.result() -# self.c2.delete_queue(q1) #.result() + # self.c2.delete_queue(q1) #.result() time.sleep(30) self.assertTrue(con1.cancelled) @@ -57,7 +58,8 @@ class TestDouble(unittest.TestCase): fut.result() try: - con2, fut2 = self.c2.consume(q, fail_on_first_time_resource_locked=True) + con2, fut2 = self.c2.consume(q, + fail_on_first_time_resource_locked=True) fut2.result() except AMQPError as e: self.assertEquals(e.reply_code, RESOURCE_LOCKED) diff --git a/tests/test_clustering/test_exchanges.py b/tests/test_clustering/test_exchanges.py index 1a6e7a83f8e216fc5a163bd0168f82e4f678ccdc..65b028768191a656efcfd985a71f567ceb09fb77 100644 --- a/tests/test_clustering/test_exchanges.py +++ b/tests/test_clustering/test_exchanges.py @@ -3,12 +3,13 @@ from __future__ import print_function, absolute_import, division import six import unittest import time, logging, threading -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage, Exchange from coolamqp.clustering import Cluster, MessageReceived, NothingMuch from coolamqp.exceptions import AMQPError import time -#todo handle bad auth +# todo handle bad auth NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) logging.basicConfig(level=logging.DEBUG) @@ -28,8 +29,10 @@ class TestExchanges(unittest.TestCase): def test_fanout(self): x = Exchange(u'jola', type='direct', auto_delete=True) - c1, f1 = self.c.consume(Queue('one', exchange=x, exclusive=True), no_ack=True) - c2, f2 = self.c.consume(Queue('two', exchange=x, exclusive=True), no_ack=True) + c1, f1 = self.c.consume(Queue('one', exchange=x, exclusive=True), + no_ack=True) + c2, f2 = self.c.consume(Queue('two', exchange=x, exclusive=True), + no_ack=True) f1.result() f2.result() @@ -39,9 +42,3 @@ class TestExchanges(unittest.TestCase): self.assertIsInstance(self.c.drain(2), MessageReceived) self.assertIsInstance(self.c.drain(2), MessageReceived) self.assertIsInstance(self.c.drain(2), NothingMuch) - - - - - - diff --git a/tests/test_clustering/test_things.py b/tests/test_clustering/test_things.py index e158e0406194101802f96504a6ce9ef93612f33f..061bf436a2a81027d684e321f97dfe6e9a34d15a 100644 --- a/tests/test_clustering/test_things.py +++ b/tests/test_clustering/test_things.py @@ -4,19 +4,22 @@ from __future__ import print_function, absolute_import, division import six import unittest import time, logging, threading, monotonic, warnings -from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, ReceivedMessage, Exchange +from coolamqp.objects import Message, MessageProperties, NodeDefinition, Queue, \ + ReceivedMessage, Exchange from coolamqp.clustering import Cluster, MessageReceived, NothingMuch import time + NODE = NodeDefinition('127.0.0.1', 'guest', 'guest', heartbeat=20) logging.basicConfig(level=logging.DEBUG) class TestConnecting(unittest.TestCase): - def test_on_fail(self): q = {'failed': False} - c = Cluster(NodeDefinition('127.0.0.1', 'xguest', 'xguest', heartbeat=20), on_fail=lambda: q.update(failed=True)) + c = Cluster( + NodeDefinition('127.0.0.1', 'xguest', 'xguest', heartbeat=20), + on_fail=lambda: q.update(failed=True)) c.start() time.sleep(5) c.shutdown() @@ -54,7 +57,7 @@ class TestConnecting(unittest.TestCase): user='guest', password='guest') - self.assertEquals(node.virtual_host, '/') # default + self.assertEquals(node.virtual_host, '/') # default def test_amqpconnstring_port(self): node = NodeDefinition('amqp://lol:lol@lol:4123/vhost') diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 516ff965e963fb5e4feaf50475f7b0d2077122ea..33c11786d5aec6ad818b54e9dd2485671e723383 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -13,4 +13,3 @@ class TestExcs(unittest.TestCase): self.assertTrue(u'100' in str(e)) self.assertTrue(u'wtf' in str(e)) self.assertTrue(repr(e).startswith(u'AMQPError')) - diff --git a/tests/test_framing/test_compilation.py b/tests/test_framing/test_compilation.py index 51840518a40453d0bbbc9b88a13e6fec9d9f4e09..90632c48724f4628d4061994af8f5062d57180c6 100644 --- a/tests/test_framing/test_compilation.py +++ b/tests/test_framing/test_compilation.py @@ -6,6 +6,7 @@ import unittest class TestCompilation(unittest.TestCase): def test_comp(self): - from coolamqp.framing.compilation.compile_definitions import compile_definitions - compile_definitions(xml_file='resources/amqp0-9-1.extended.xml', out_file='/tmp/definitions.py') - + from coolamqp.framing.compilation.compile_definitions import \ + compile_definitions + compile_definitions(xml_file='resources/amqp0-9-1.extended.xml', + out_file='/tmp/definitions.py') diff --git a/tests/test_objects.py b/tests/test_objects.py index e3a109d0ef84031ec3b61bed2fbebc59d73a8f50..f7e5569d0aee2945218cc2c03f6109420aabc914 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -10,7 +10,6 @@ from coolamqp.objects import NodeDefinition, MessageProperties class TestObjects(unittest.TestCase): def test_node_definition_from_amqp(self): - n1 = NodeDefinition(u'amqp://ala:ma@kota/psa') self.assertEquals(n1.user, u'ala') diff --git a/tests/utils.py b/tests/utils.py index 422c366707b99a82d48c9ffda46155bbf50a5938..17481f70a2f76883c6ca007f735b1f8d409af23f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,8 @@ import socket import collections import monotonic -from coolamqp import Cluster, ClusterNode, ConnectionUp, ConnectionDown, ConnectionUp, ConsumerCancelled +from coolamqp import Cluster, ClusterNode, ConnectionUp, ConnectionDown, \ + ConnectionUp, ConsumerCancelled from coolamqp.backends.base import AMQPBackend, ConnectionFailedError @@ -21,7 +22,7 @@ class CoolAMQPTestCase(unittest.TestCase): Base class for all CoolAMQP tests. Creates na AMQP connection, provides methods for easy interfacing, and other utils. """ - INIT_AMQP = True # override on child classes + INIT_AMQP = True # override on child classes def setUp(self): if self.INIT_AMQP: @@ -50,7 +51,7 @@ class CoolAMQPTestCase(unittest.TestCase): if type(q) in types: types.remove(type(q)) if len(types) > 0: - self.fail('Not found %s' % (''.join(map(str, types)), )) + self.fail('Not found %s' % (''.join(map(str, types)),)) def drainTo(self, type_, timeout, forbidden=[ConsumerCancelled]): """ @@ -72,7 +73,7 @@ class CoolAMQPTestCase(unittest.TestCase): q = self.amqp.drain(1) if isinstance(q, type_): return q - self.fail('Did not find %s' % (type_, )) + self.fail('Did not find %s' % (type_,)) def takes_less_than(self, max_time): """ @@ -87,14 +88,14 @@ class CoolAMQPTestCase(unittest.TestCase): return TakesLessThanCM(self, max_time) # ======failures - def single_fail_amqp(self): # insert single failure + def single_fail_amqp(self): # insert single failure sock = self.amqp.thread.backend.channel.connection.transport.sock self.amqp.thread.backend.channel.connection.transport.sock = FailbowlSocket() self.amqp.thread.backend.channel.connection = None # 'connection already closed' or sth like that sock.close() - def fail_amqp(self): # BROKER DEAD: SWITCH ON + def fail_amqp(self): # BROKER DEAD: SWITCH ON self.old_backend = self.amqp.backend self.amqp.backend = FailbowlBackend @@ -104,15 +105,15 @@ class CoolAMQPTestCase(unittest.TestCase): del self.old_backend def restart_rmq(self): # simulate a broker restart - self.fail_amqp() - self.single_fail_amqp() - time.sleep(3) - self.unfail_amqp() + self.fail_amqp() + self.single_fail_amqp() + time.sleep(3) + self.unfail_amqp() - self.drainTo([ConnectionDown, ConnectionUp], [5, 20]) + self.drainTo([ConnectionDown, ConnectionUp], [5, 20]) def new_amqp_connection(self, consume_connectionup=True): - return AMQPConnectionCM(self, consume_connectionup=consume_connectionup) + return AMQPConnectionCM(self, consume_connectionup=consume_connectionup) class TakesLessThanCM(object): @@ -122,7 +123,7 @@ class TakesLessThanCM(object): def __enter__(self, testCase, max_time): self.started_at = time.time() - return lambda: time.time() - self.started_at > self.max_time # is_late + return lambda: time.time() - self.started_at > self.max_time # is_late def __exit__(self, tp, v, tb): self.test.assertLess(time.time() - self.started_at, self.max_time) @@ -138,6 +139,7 @@ class AMQPConnectionCM(object): amqp2.consume(...) """ + def __init__(self, testCase, consume_connectionup): self.test = testCase self.consume_connectionup = consume_connectionup @@ -162,7 +164,7 @@ class FailbowlBackend(AMQPBackend): class FailbowlSocket(object): def __getattr__(self, item): def failbowl(*args, **kwargs): - time.sleep(1) # hang and fail + time.sleep(1) # hang and fail raise socket.error def sleeper(*args, **kwargs): @@ -172,4 +174,3 @@ class FailbowlSocket(object): return sleeper else: return failbowl -