PageSourceSearch

https://www.rabbitmq.com/assets/js/33f00ec3.820cb3b4.js

js rabbitmq.com collected 2026-10-01 06:29:02 UTC 46,660 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkrabbitmq_website=self.webpackChunkrabbitmq_website||[]).push([["11485"],{79857(e,n,s){s.r(n),s.d(n,{metadata:()=>i,default:()=>h,frontMatter:()=>a,contentTitle:()=>c,toc:()=>o,assets:()=>d});var i=JSON.parse('{"id":"stomp","title":"STOMP Plugin","description":"\x3c!--","source":"@site/versioned_docs/version-4.3/stomp.md","sourceDirName":".","slug":"/stomp","permalink":"/docs/stomp","draft":false,"unlisted":false,"editUrl":"https://github.com/rabbitmq/rabbitmq-website/tree/main/versioned_docs/version-4.3/stomp.md","tags":[],"version":"4.3","frontMatter":{"title":"STOMP Plugin"},"sidebar":"docsSidebar","previous":{"title":"Static Shovels","permalink":"/docs/shovel-static"},"next":{"title":"Web STOMP Plugin","permalink":"/docs/web-stomp"}}'),t=s(74848),r=s(28453);let a={title:"STOMP Plugin"},c="STOMP Plugin",d={},o=[{value:"Overview",id:"overview",level:2},{value:"Enabling the Plugin",id:"enabling-plugin",level:2},{value:"Plugin Configuration",id:"configuration",level:2},{value:"TCP Listeners",id:"tcp-listeners",level:3},{value:"TCP Listener Options",id:"tcp-listener-options",level:4},{value:"TLS Support",id:"tls",level:3},{value:"Default User",id:"default-credentials",level:3},{value:"Authentication with TLS/x509 client certificates",id:"tls-certificate-authentication",level:3},{value:"Implicit Connect",id:"cta.ic",level:3},{value:"Proxy Protocol",id:"proxy-protocol",level:3},{value:"Frame Size Limit",id:"frame-size-limit",level:3},{value:"Destinations",id:"d",level:2},{value:"AMQP 0-9-1 Semantics",id:"amqp-0-9-1-semantics",level:3},{value:"Exchange Destinations",id:"d.ed",level:3},{value:"Queue Destinations",id:"d.qd",level:3},{value:"AMQP 0-9-1 Semantics",id:"amqp-0-9-1-semantics-1",level:4},{value:"AMQ Queue Destinations",id:"d.aqd",level:3},{value:"AMQP 0-9-1 Semantics",id:"amqp-0-9-1-semantics-2",level:4},{value:"Topic Destinations",id:"d.td",level:3},{value:"AMQP 0-9-1 Semantics",id:"amqp-0-9-1-semantics-3",level:4},{value:"Durable Topic Subscriptions",id:"d.dts",level:3},{value:"Creating a Durable Subscription",id:"creating-a-durable-subscription",level:4},{value:"AMQP 0-9-1 Semantics",id:"amqp-0-9-1-semantics-4",level:4},{value:"Deleting a Durable Subscription",id:"deleting-a-durable-subscription",level:4},{value:"Temp Queue Destinations",id:"d.tqd",level:3},{value:"AMQP 0-9-1 Semantics",id:"amqp-0-9-1-semantics-5",level:4},{value:"User generated queue names for Topic and Exchange destinations",id:"d.ugqn",level:3},{value:"Controlling RabbitMQ Queue Parameters with STOMP",id:"queue-parameters",level:2},{value:"Using Policies with STOMP",id:"policies",level:2},{value:"Protocol Extensions and Restrictions",id:"extensions-and-restrictions",level:2},{value:"Connection and Virtual Hosts",id:"pear.c",level:3},{value:"Message Persistence",id:"pear.mp",level:3},{value:"ACK and NACK",id:"ack-nack",level:3},{value:"Prefetch",id:"pear.p",level:3},{value:"Stream Support",id:"stream-support",level:3},{value:"Header prohibited on <code>SEND</code>",id:"pear.hpos",level:3},{value:"Queue Properties",id:"pear.ap",level:3},{value:"Optional Queue Properties",id:"optional-queue-properties",level:3},{value:"Queue Immutability",id:"queue-immutability",level:3}];function l(e){let n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"stomp-plugin",children:"STOMP Plugin"})}),"\n",(0,t.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,t.jsxs)(n.p,{children:["RabbitMQ supports ",(0,t.jsx)(n.a,{href:"http://stomp.github.io",children:"STOMP"})," via a plugin that ships\nin the core distribution. The plugin supports STOMP versions 1.0 through ",(0,t.jsx)(n.a,{href:"https://stomp.github.io/stomp-specification-1.2.html",children:"1.2"}),"\nwith some ",(0,t.jsx)(n.a,{href:"#extensions-and-restrictions",children:"extensions and restrictions"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["STOMP clients can interoperate with other protocols. All the functionality in\nthe ",(0,t.jsx)(n.a,{href:"./management",children:"management UI"})," and several other plugins can be\nused with STOMP, although there may be some limitations or the need to\ntweak the defaults."]}),"\n",(0,t.jsx)(n.h2,{id:"enabling-plugin",children:"Enabling the Plugin"}),"\n",(0,t.jsxs)(n.p,{children:["The STOMP plugin is included in the RabbitMQ distribution. Before clients can successfully\nconnect, it must be enabled using ",(0,t.jsx)(n.a,{href:"./cli",children:"rabbitmq-plugins"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"rabbitmq-plugins enable rabbitmq_stomp\n"})}),"\n",(0,t.jsx)(n.h2,{id:"configuration",children:"Plugin Configuration"}),"\n",(0,t.jsx)(n.h3,{id:"tcp-listeners",children:"TCP Listeners"}),"\n",(0,t.jsxs)(n.p,{children:["When no configuration is specified the STOMP Adapter will listen on\nall interfaces on port 61613 and have a default user login/passcode\nof ",(0,t.jsx)(n.code,{children:"guest"}),"/",(0,t.jsx)(n.code,{children:"guest"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["To change the listener port, edit your\n",(0,t.jsx)(n.a,{href:"./configure#configuration-files",children:"Configuration file"}),",\nto contain a ",(0,t.jsx)(n.code,{children:"tcp_listeners"})," variable for the ",(0,t.jsx)(n.code,{children:"rabbitmq_stomp"})," application."]}),"\n",(0,t.jsx)(n.p,{children:"For example, a minimalistic configuration file which changes the listener\nport to 12345 would look like:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.listeners.tcp.1 = 12345\n"})}),"\n",(0,t.jsx)(n.p,{children:"while one which changes the listener to listen only on localhost (for\nboth IPv4 and IPv6) would look like:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.listeners.tcp.1 = 127.0.0.1:61613\nstomp.listeners.tcp.2 = ::1:61613\n"})}),"\n",(0,t.jsx)(n.h4,{id:"tcp-listener-options",children:"TCP Listener Options"}),"\n",(0,t.jsx)(n.p,{children:"The plugin supports TCP listener option configuration."}),"\n",(0,t.jsxs)(n.p,{children:["The settings use a common prefix, ",(0,t.jsx)(n.code,{children:"stomp.tcp_listen_options"}),", and control\nthings such as TCP buffer sizes, inbound TCP connection queue length, whether ",(0,t.jsx)(n.a,{href:"./heartbeats#tcp-keepalives",children:"TCP keepalives"}),"\nare enabled and so on. See the ",(0,t.jsx)(n.a,{href:"./networking",children:"Networking guide"})," for details."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.listeners.tcp.1 = 127.0.0.1:61613\nstomp.listeners.tcp.2 = ::1:61613\n\nstomp.tcp_listen_options.backlog = 4096\nstomp.tcp_listen_options.recbuf  = 131072\nstomp.tcp_listen_options.sndbuf  = 131072\n\nstomp.tcp_listen_options.keepalive = true\nstomp.tcp_listen_options.nodelay   = true\n\nstomp.tcp_listen_options.exit_on_close = true\nstomp.tcp_listen_options.send_timeout  = 120\n"})}),"\n",(0,t.jsx)(n.h3,{id:"tls",children:"TLS Support"}),"\n",(0,t.jsxs)(n.p,{children:["To use TLS for STOMP connections, ",(0,t.jsx)(n.a,{href:"./ssl",children:"TLS must be configured"})," in the broker. To enable\nTLS-enabled STOMP connections, add a TLS listener for STOMP using the ",(0,t.jsx)(n.code,{children:"stomp.listeners.ssl.*"})," configuration keys."]}),"\n",(0,t.jsx)(n.p,{children:"The plugin will use core RabbitMQ server\ncertificates and ke
1y (just like AMQP 0-9-1 and AMQP 1.0 listeners do):"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"ssl_options.cacertfile = /path/to/tls/ca_certificate.pem\nssl_options.certfile   = /path/to/tls/server_certificate.pem\nssl_options.keyfile    = /path/to/tls/server_key.pem\nssl_options.verify     =  verify_peer\nssl_options.fail_if_no_peer_cert = true\n\nstomp.listeners.tcp.1 = 61613\n# default TLS-enabled port for STOMP connections\nstomp.listeners.ssl.1 = 61614\n"})}),"\n",(0,t.jsx)(n.p,{children:"This configuration creates a standard TCP listener on port 61613 and\na TLS listener on port 61614."}),"\n",(0,t.jsx)(n.p,{children:"When a TLS listener is set up, you may want to deactivate all non-TLS ones.\nThis can be configured like so:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.listeners.tcp   = none\nstomp.listeners.ssl.1 = 61614\n"})}),"\n",(0,t.jsx)(n.h3,{id:"default-credentials",children:"Default User"}),"\n",(0,t.jsxs)(n.p,{children:["The RabbitMQ STOMP adapter allows ",(0,t.jsx)(n.code,{children:"CONNECT"})," frames to omit the ",(0,t.jsx)(n.code,{children:"login"}),"\nand ",(0,t.jsx)(n.code,{children:"passcode"})," headers if a default is configured."]}),"\n",(0,t.jsxs)(n.p,{children:["To configure a default login and passcode, add a ",(0,t.jsx)(n.code,{children:"default_user"}),"\nsection to the ",(0,t.jsx)(n.code,{children:"rabbitmq_stomp"})," application configuration. For example:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.default_user = guest\nstomp.default_pass = guest\n"})}),"\n",(0,t.jsxs)(n.p,{children:["The configuration example above makes ",(0,t.jsx)(n.code,{children:"guest"}),"/",(0,t.jsx)(n.code,{children:"guest"})," the default\nlogin/passcode pair."]}),"\n",(0,t.jsx)(n.h3,{id:"tls-certificate-authentication",children:"Authentication with TLS/x509 client certificates"}),"\n",(0,t.jsx)(n.p,{children:"The plugin can authenticate TLS-enabled connections by extracting\na name from the client's TLS (x509) certificate, without using a password."}),"\n",(0,t.jsxs)(n.p,{children:["For safety the server must be ",(0,t.jsx)(n.a,{href:"#tls",children:"configured with the TLS options"}),"\n",(0,t.jsx)(n.code,{children:"fail_if_no_peer_cert"})," set to ",(0,t.jsx)(n.code,{children:"true"})," and ",(0,t.jsx)(n.code,{children:"verify"})," set to ",(0,t.jsx)(n.code,{children:"verify_peer"}),", to\nforce all TLS clients to have a verifiable client certificate."]}),"\n",(0,t.jsxs)(n.p,{children:["To switch this feature on, set ",(0,t.jsx)(n.code,{children:"ssl_cert_login"})," to ",(0,t.jsx)(n.code,{children:"true"})," for the\n",(0,t.jsx)(n.code,{children:"rabbitmq_stomp"})," application. For example:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.ssl_cert_login = true\n"})}),"\n",(0,t.jsx)(n.p,{children:"By default this will set the username to an RFC4514-ish string form of\nthe certificate's subject's Distinguished Name, similar to that\nproduced by OpenSSL's \"-nameopt RFC2253\" option."}),"\n",(0,t.jsx)(n.p,{children:"To use the Common Name instead, add:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"ssl_cert_login_from = common_name\n"})}),"\n",(0,t.jsx)(n.p,{children:"to your configuration."}),"\n",(0,t.jsx)(n.p,{children:"Note that:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"The authenticated user must exist in the configured authentication / authorisation backend(s)."}),"\n",(0,t.jsxs)(n.li,{children:["Clients must ",(0,t.jsx)(n.strong,{children:"not"})," supply ",(0,t.jsx)(n.code,{children:"login"})," and ",(0,t.jsx)(n.code,{children:"passcode"})," headers."]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"cta.ic",children:"Implicit Connect"}),"\n",(0,t.jsxs)(n.p,{children:["If you configure a default user or use SSL client certificate\nauthentication, you can also choose to allow clients to omit the\n",(0,t.jsx)(n.code,{children:"CONNECT"})," frame entirely. In this mode, if the first frame sent on a\nsession is not a ",(0,t.jsx)(n.code,{children:"CONNECT"}),", the client is automatically connected as\nthe default user or the user supplied in the SSL certificate."]}),"\n",(0,t.jsxs)(n.p,{children:["To enable implicit connect, set ",(0,t.jsx)(n.code,{children:"implicit_connect"})," to ",(0,t.jsx)(n.code,{children:"true"})," for the\n",(0,t.jsx)(n.code,{children:"rabbit_stomp"})," application. For example:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.default_user = guest\nstomp.default_pass = guest\nstomp.implicit_connect = true\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Implicit connect is ",(0,t.jsx)(n.em,{children:"not"})," enabled by default."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Note:"})," A client causing an implicit connect will ",(0,t.jsx)(n.em,{children:"not"})," receive a\n",(0,t.jsx)(n.code,{children:"CONNECTED"})," frame from the server."]}),"\n",(0,t.jsx)(n.h3,{id:"proxy-protocol",children:"Proxy Protocol"}),"\n",(0,t.jsxs)(n.p,{children:["The STOMP plugin supports the ",(0,t.jsx)(n.a,{href:"http://www.haproxy.org/download/3.1/doc/proxy-protocol.txt",children:"proxy protocol"}),".\nThis feature is turned off by default. To turn it on for STOMP clients:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.proxy_protocol = true\n"})}),"\n",(0,t.jsxs)(n.p,{children:["See the ",(0,t.jsx)(n.a,{href:"./networking#proxy-protocol",children:"Networking Guide"})," for more information\nabout the proxy protocol."]}),"\n",(0,t.jsx)(n.h3,{id:"frame-size-limit",children:"Frame Size Limit"}),"\n",(0,t.jsx)(n.p,{children:"By default frame size limit is 4Mb. When a frame exceeds the limit it's an error and connection closed."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.max_frame_size = 4 * 1024 * 1024\n"})}),"\n",(0,t.jsx)(n.h2,{id:"d",children:"Destinations"}),"\n",(0,t.jsxs)(n.p,{children:["The STOMP specification does not prescribe what kinds of destinations\na broker must support, instead the value of the ",(0,t.jsx)(n.code,{children:"destination"})," header\nin ",(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"MESSAGE"})," frames is broker-specific. The RabbitMQ STOMP\nadapter supports a number of different destination types:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/exchange"})," -- ",(0,t.jsx)(n.code,{children:"SEND"})," to arbitrary routing keys and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," to\narbitrary binding patterns;"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/queue"})," -- ",(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," to queues managed by the STOMP\ngateway;"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/amq/queue"})," -- ",(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," to queues created outside the\nSTOMP gateway;"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/topic"})," -- ",(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," to transient and durable topics;"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"/temp-queue/"})," -- create temporary queues (in ",(0,t.jsx)(n.code,{children:"reply-to"})," headers only)."]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"amqp-0-9-1-semantics",children:"AMQP 0-9-1 Semantics"}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"destination"})," header on a ",(0,t.jsx)(n.code,{children:"MESSAGE"})," frame is set as though the\nmessage originated from a ",(0,t.jsx)(n.code,{children:"SEND"})," frame:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["messages published to the default exchange are given the destination\n",(0,t.jsx)(n.code,{children:"/queue/"}),(0,t.jsx)(n.em,{children:"queuename"}),";"]}),"\n",(0,t.jsxs)(n.li,{children:["messages published to ",(0,t.jsx)(n.code,{children:"amq.topic"})," are given the destination\n",(0,t.jsx)(n.code,{children:"/topic/"}),(0,t.jsx)(n.em,{children:"routing_key"}),";"]}),"\n",(0,t.jsxs)(n.li,{children:["all other messages are given the destination\n",(0,t.jsx)(n.code,{children:"/exchange/"}),(0,t.jsx)(n.em,{children:"exchange_name"}),"[",(0,t.jsx)(n.code,{children:"/"}),(0,t.jsx)(n.em,{children:"routing_key"}),"]."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["If ",(0,t.jsx)(n.code,{children:"/"}),", ",(0,t.jsx)(n.code,{children:"%"})," or non-ascii bytes are in the ",(0,t.jsx)(n.em,{children:"queuename"}),", ",(0,t.jsx)(n.em,{children:"exchange_name"}),"\nor ",(0,t.jsx)(n.em,{children:"routing_key"}),", they are each replaced with the sequence ",(0,t.jsx)(n.code,{children:"%"}),(0,t.jsx)(n.em,{children:"dd"}),",\nwhere ",(0,t.jsx)(n.em,{children:"dd"})," is the hexadecimal code for the byte."]}),"\n",(0,t.jsxs)(n.p,{children:["Because of these rules the destination on a ",(0,t.jsx)(n.code,{children:"MESSAGE"})," frame may not\nexactly match that on a ",(0,t.jsx)(n.code,{children:"SEND"})," that published it."]}),"\n",(0,t.jsx)(n.p,{children:"Different destinations have different queue parameter defaults.\nThey can be controlled explicitly via headers, as explained further\nin this guide."}),"\n",(0,t.jsx)(n.h3,{id:"d.ed",children:"Exchange Destinations"}),"\n",(0,t.jsxs)(n.p,{children:["Any exchange/queue or exchange/routing-key combination can be accessed\nusing destinations prefixed with ",(0,t.jsx)(n.code,{children:"/exchange"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames, a destination of the form\n",(0,t.jsx)(n.code,{children:"/exchange/<name>[/<pattern>]"})," can be used. This destination:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["creates an exclusive, auto-delete queue on ",(0,t.jsx)(n.code,{children:"<name>"})," exchange;"]}),"\n",(0,t.jsxs)(n.li,{children:["if ",(0,t.jsx)(n.code,{children:"<pattern>"})," is supplied, binds the queue to ",(0,t.jsx)(n.code,{children:"<name>"})," exchange\nusing ",(0,t.jsx)(n.code,{children:"<pattern>"}),"; and"]}),"\n",(0,t.jsx)(n.li,{children:"registers a subscription against the queue, for the current STOMP session."}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SEND"})," frames, a destination of the form\n",(0,t.jsx)(n.code,{children:"/exchange/<name>[/<routing-key>]"})," can be used. This destination:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["sends to exchange ",(0,t.jsx)(n.code,{children:"<name>"})," with the routing key ",(0,t.jsx)(n.code,{children:"<routing-key>"}),"."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Note:"})," Exchange destinations are ",(0,t.jsx)(n.em,{children:"not"})," suitable for\nconsuming messages from an existing queue. A new queue is created for\neach subscriber and is bound to the specified exchange using the\nsupplied routing key. To work with existing queues, use\n",(0,t.jsx)(n.a,{href:"#d.aqd",children:(0,t.jsx)(n.code,{children:"/amq/queue"})})," destinations."]}),"\n",(0,t.jsx)(n.h3,{id:"d.qd",children:"Queue Destinations"}),"\n",(0,t.jsxs)(n.p,{children:["For simple queues, destinations of the form ",(0,t.jsx)(n.code,{children:"/queue/<name>"})," can be\nused."]}),"\n",(0,t.jsx)(n.p,{children:"Queue destinations deliver each message to at most one\nsubscriber. Messages sent when no subscriber exists will be queued\nuntil a subscriber connects to the queue."}),"\n",(0,t.jsx)(n.h4,{id:"amqp-0-9-1-semantics-1",children:"AMQP 0-9-1 Semantics"}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames, these destinations create a shared queue ",(0,t.jsx)(n.code,{children:"<name>"}),". A\nsubscription against the queue ",(0,t.jsx)(n.code,{children:"<name>"})," is created for the current STOMP\nsession."]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SEND"})," frames, a shared queue ",(0,t.jsx)(n.code,{children:"<name>"})," is created on the ",(0,t.jsx)(n.em,{children:"first"})," ",(0,t.jsx)(n.code,{children:"SEND"})," to\nthis destination in this session, but not subsequently. The message is sent to\nthe default exchange with the routing key ",(0,t.jsx)(n.code,{children:"<name>"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"If no queue parameters are specified, queue will be assumed to be\ndurable, non-exclusive, non-autodeleted."}),"\n",(0,t.jsx)(n.h3,{id:"d.aqd",children:"AMQ Queue Destinations"}),"\n",(0,t.jsxs)(n.p,{children:["To address existing queues created outside the STOMP adapter,\ndestinations of the form ",(0,t.jsx)(n.code,{children:"/amq/queue/<name>"})," can be used."]}),"\n",(0,t.jsx)(n.h4,{id:"amqp-0-9-1-semantics-2",children:"AMQP 0-9-1 Semantics"}),"\n",(0,t.jsxs)(n.p,{children:["For both ",(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames no queue is created.\nFor ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames, it is an error if the queue does not exist."]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SEND"})," frames, the message is sent directly to the existing queue named\n",(0,t.jsx)(n.code,{children:"<name>"})," via the default exchange."]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames, a subscription against the existing queue ",(0,t.jsx)(n.code,{children:"<name>"})," is\ncreated for the current STOMP session."]}),"\n",(0,t.jsx)(n.p,{children:"If no queue parameters are specified, queue will be assumed to be\ndurable, non-exclusive, non-autodeleted."}),"\n",(0,t.jsx)(n.h3,{id:"d.td",children:"Topic Destinations"}),"\n",(0,t.jsxs)(n.p,{children:["Perhaps the most common destination type used by STOMP clients is ",(0,t.jsx)(n.code,{children:"/topic/<name>"}),".\nThey perform topic matching on publishing messages against subscriber patterns\nand can route a message to multiple subscribers (each gets its own copy).\nTopic destinations supp
1ort all the routing patterns of ",(0,t.jsx)(n.a,{href:"/tutorials/amqp-concepts",children:"AMQP 0-9-1\ntopic exchanges"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Messages sent to a topic destination that has no active subscribers\nare simply discarded."}),"\n",(0,t.jsx)(n.h4,{id:"amqp-0-9-1-semantics-3",children:"AMQP 0-9-1 Semantics"}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SEND"})," frames, the message is sent to the ",(0,t.jsx)(n.code,{children:"amq.topic"})," exchange\nwith the routing key ",(0,t.jsx)(n.code,{children:"<name>"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames, an autodeleted, non-durable queue is created and bound to the\n",(0,t.jsx)(n.code,{children:"amq.topic"})," exchange with routing key ",(0,t.jsx)(n.code,{children:"<name>"}),". A subscription is\ncreated against the queue."]}),"\n",(0,t.jsxs)(n.p,{children:["A different default exchange than ",(0,t.jsx)(n.code,{children:"amq.topic"})," can be specified\nusing the ",(0,t.jsx)(n.code,{children:"stomp.default_topic_exchange"})," configuration setting:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.default_topic_exchange = some.exchange\n"})}),"\n",(0,t.jsx)(n.h3,{id:"d.dts",children:"Durable Topic Subscriptions"}),"\n",(0,t.jsx)(n.p,{children:"The STOMP adapter supports durable topic subscriptions. Durable\nsubscriptions allow clients to disconnect from and reconnect to the\nSTOMP broker as needed, without missing messages that are sent to the\ntopic."}),"\n",(0,t.jsxs)(n.p,{children:["Topics are neither durable nor transient, instead ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.strong,{children:"subscriptions"})}),"\nare durable or transient. Durable and transient can be mixed against a\ngiven topic."]}),"\n",(0,t.jsx)(n.h4,{id:"creating-a-durable-subscription",children:"Creating a Durable Subscription"}),"\n",(0,t.jsxs)(n.p,{children:["To create a durable subscription, set the ",(0,t.jsx)(n.code,{children:"durable"})," header to\n",(0,t.jsx)(n.code,{children:"true"})," in the ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frame. ",(0,t.jsx)(n.code,{children:"persistent"})," is also supported as an alias for\n",(0,t.jsx)(n.code,{children:"durable"})," for backwards compatibility with earlier plugin versions."]}),"\n",(0,t.jsxs)(n.p,{children:["When creating a durable subscription to a topic destination,\nset ",(0,t.jsx)(n.code,{children:"auto-delete"})," to ",(0,t.jsx)(n.code,{children:"false"})," to make sure the queue that backs your\nsubscription is not deleted when last subscriber disconnects."]}),"\n",(0,t.jsxs)(n.p,{children:["When creating a durable subscription,\nthe ",(0,t.jsx)(n.code,{children:"id"})," header must be specified. For example:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"SUBSCRIBE\ndestination:/topic/my-durable\nid:1234\ndurable:true\nauto-delete:false\n"})}),"\n",(0,t.jsx)(n.h4,{id:"amqp-0-9-1-semantics-4",children:"AMQP 0-9-1 Semantics"}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SEND"})," frames, the message is sent to the ",(0,t.jsx)(n.code,{children:"amq.topic"})," exchange\nwith the routing key ",(0,t.jsx)(n.code,{children:"<name>"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames, a ",(0,t.jsx)(n.em,{children:"shared"})," queue is created for each distinct\nsubscription ID x destination pair, and bound to the ",(0,t.jsx)(n.code,{children:"amq.topic"}),"\nexchange with routing key ",(0,t.jsx)(n.code,{children:"<name>"}),". A subscription is created against\nthe queue."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.em,{children:"Note:"})," a different default exchange than ",(0,t.jsx)(n.code,{children:"amq.topic"})," can be specified\nusing the ",(0,t.jsx)(n.code,{children:"stomp.default_topic_exchange"})," configuration setting."]}),"\n",(0,t.jsx)(n.h4,{id:"deleting-a-durable-subscription",children:"Deleting a Durable Subscription"}),"\n",(0,t.jsxs)(n.p,{children:["To permanently delete a durable subscription, send an ",(0,t.jsx)(n.code,{children:"UNSUBSCRIBE"})," frame for\nthe subscription ID with the same ",(0,t.jsx)(n.code,{children:"durable"})," and ",(0,t.jsx)(n.code,{children:"auto-delete"})," header values as when\nsubscribing."]}),"\n",(0,t.jsx)(n.p,{children:"For example:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"UNSUBSCRIBE\nid:1234\ndurable:true\nauto-delete:false\n"})}),"\n",(0,t.jsx)(n.h3,{id:"d.tqd",children:"Temp Queue Destinations"}),"\n",(0,t.jsxs)(n.p,{children:["Temp queue destinations allow you to define temporary destinations\nin the ",(0,t.jsx)(n.code,{children:"reply-to"})," header of a ",(0,t.jsx)(n.code,{children:"SEND"})," frame."]}),"\n",(0,t.jsx)(n.p,{children:"Temp queues are managed by the broker and their identities are private to\neach session -- there is no need to choose distinct names for\ntemporary queues in distinct sessions."}),"\n",(0,t.jsxs)(n.p,{children:["To use a temp queue, put the ",(0,t.jsx)(n.code,{children:"reply-to"})," header on a ",(0,t.jsx)(n.code,{children:"SEND"})," frame and\nuse a header value starting with ",(0,t.jsx)(n.code,{children:"/temp-queue/"}),". For example:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"SEND\ndestination:/queue/reply-test\nreply-to:/temp-queue/foo\n\nHello World!\n"})}),"\n",(0,t.jsxs)(n.p,{children:["This frame creates a temporary queue (with a generated name) that is private\nto the session and automatically subscribes to that queue.\nA different session that uses ",(0,t.jsx)(n.code,{children:"reply-to:/temp-queue/foo"})," will have a new,\ndistinct queue created."]}),"\n",(0,t.jsxs)(n.p,{children:["The internal subscription id is a concatenation of the string\n",(0,t.jsx)(n.code,{children:"/temp-queue/"})," and the temporary queue (so ",(0,t.jsx)(n.code,{children:"/temp-queue/foo"}),"\nin this example). The subscription id can be used to identify reply\nmessages. Reply messages cannot be identified from the ",(0,t.jsx)(n.code,{children:"destination"}),"\nheader, which will be different from the value in the ",(0,t.jsx)(n.code,{children:"reply-to"}),"\nheader. The internal subscription uses auto-ack mode and it cannot be\ncancelled."]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"/temp-queue/"})," destination is ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.strong,{children:"not"})})," the name of the destination\nthat the receiving client uses when sending the reply. Instead, the\nreceiving client can obtain the (real) reply destination queue name\nfrom the ",(0,t.jsx)(n.code,{children:"reply-to"})," header of the ",(0,t.jsx)(n.code,{children:"MESSAGE"})," frame.  This reply\ndestination name can then be used as the value of the ",(0,t.jsx)(n.code,{children:"destination"}),"\nheader in the ",(0,t.jsx)(n.code,{children:"SEND"})," frame sent in reply to the received\n",(0,t.jsx)(n.code,{children:"MESSAGE"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["Reply destination queue names are opaque and cannot be inferred from\nthe ",(0,t.jsx)(n.code,{children:"/temp-queue/"})," name."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.strong,{children:"must not"})})," contain ",(0,t.jsx)(n.code,{children:"/temp-queue"}),"\ndestinations in the ",(0,t.jsx)(n.code,{children:"destination"})," header. Messages cannot be sent to\n",(0,t.jsx)(n.code,{children:"/temp-queue"})," destinations, and subscriptions to reply queues are\ncreated automatically."]}),"\n",(0,t.jsx)(n.h4,{id:"amqp-0-9-1-semantics-5",children:"AMQP 0-9-1 Semantics"}),"\n",(0,t.jsxs)(n.p,{children:["Each ",(0,t.jsx)(n.code,{children:"/temp-queue/"})," corresponds to a distinct anonymous, exclusive,\nauto delete queue. As such, there is no need for explicit clean up of\nreply queues."]}),"\n",(0,t.jsx)(n.h3,{id:"d.ugqn",children:"User generated queue names for Topic and Exchange destinations"}),"\n",(0,t.jsxs)(n.p,{children:["When subscribing to an ",(0,t.jsx)(n.code,{children:"exchange"})," or ",(0,t.jsx)(n.code,{children:"topic"})," destination, RabbitMQ would generate\na queue name by default. It is possible to provide\na custom name using the ",(0,t.jsx)(n.code,{children:"x-queue-name"})," header:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"SUBSCRIBE\ndestination:/topic/alarms\nx-queue-name:my-alarms-queue\n"})}),"\n",(0,t.jsx)(n.h2,{id:"queue-parameters",children:"Controlling RabbitMQ Queue Parameters with STOMP"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"./queues",children:"Queue properties"})," can be controlled via STOMP headers:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"durable"})," (aliased as ",(0,t.jsx)(n.code,{children:"persistent"}),")"]}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"auto-delete"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"exclusive"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:'plus optional arguments ("x-arguments") for controlling dead lettering,\nqueue and message TTL, queue limits, etc:'}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-dead-letter-exchange"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-dead-letter-routing-key"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-expires"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-message-ttl"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-max-length"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-max-length-bytes"})}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"x-max-age"}
1)," (available only for ",(0,t.jsx)(n.a,{href:"./streams",children:"streams"}),")"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"x-stream-max-segment-size-bytes"})," (available only for ",(0,t.jsx)(n.a,{href:"./streams",children:"streams"}),")"]}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-overflow"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"x-max-priority"})}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"x-queue-type"})," (to be able to ",(0,t.jsx)(n.a,{href:"./quorum-queues#declaring",children:"declare"})," ",(0,t.jsx)(n.a,{href:"./quorum-queues",children:"quorum queues"})," and ",(0,t.jsx)(n.a,{href:"./streams",children:"streams"}),")"]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"The meaning of every header is the same as when a queue is declared over AMQP 0-9-1.\nPlease consult the rest of the documentation for details."}),"\n",(0,t.jsx)(n.h2,{id:"policies",children:"Using Policies with STOMP"}),"\n",(0,t.jsxs)(n.p,{children:["RabbitMQ ",(0,t.jsx)(n.a,{href:"./policies",children:"policies"})," allow for flexible,\ncentralised attribute configuration of queues and exchanges. Policies can\nbe used with queues used by the STOMP plugin."]}),"\n",(0,t.jsx)(n.p,{children:"Policies make it possible to use more RabbitMQ features with STOMP:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./dlx",children:"Dead lettering"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./ttl",children:"Queue leases and per-queue message TTL"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./maxlength",children:"Queue length limits"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All server-named queues created by the STOMP plugin are prefixed with ",(0,t.jsx)(n.code,{children:"stomp-"}),"\nwhich makes it easy to match the queues in a policy. For example, to limit\nSTOMP queue length to 1000 messages, create the following policy:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'rabbitmqctl set_policy stomp-queues "^stomp-" \'{"max-length":1000}\' --apply-to queues\n'})}),"\n",(0,t.jsxs)(n.p,{children:["with ",(0,t.jsx)(n.code,{children:"rabbitmqctl.bat"})," on Windows:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-PowerShell",children:'rabbitmqctl.bat set_policy stomp-queues "^stomp-" "{""max-length"":1000}" --apply-to queues\n'})}),"\n",(0,t.jsx)(n.p,{children:"Note that only one policy is applied to a queue at a time, so to specify\nmultiple arguments (e.g. queue length limit and dead lettering) one\nneeds to put them into a single policy."}),"\n",(0,t.jsx)(n.h2,{id:"extensions-and-restrictions",children:"Protocol Extensions and Restrictions"}),"\n",(0,t.jsxs)(n.p,{children:["The RabbitMQ STOMP adapter relaxes the protocol on ",(0,t.jsx)(n.code,{children:"CONNECT"}),"\nand supports a number of non-standard headers on certain\nframes. These extra headers provide access to features that are not\ndescribed in the STOMP specs. In addition, we prohibit some headers which\nare reserved for server use. The details are given below."]}),"\n",(0,t.jsx)(n.h3,{id:"pear.c",children:"Connection and Virtual Hosts"}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"CONNECT"})," (or ",(0,t.jsx)(n.code,{children:"STOMP"}),") frame in\n",(0,t.jsx)(n.a,{href:"http://stomp.github.io/stomp-specification-1.1.html",children:"STOMP 1.1"})," has a\nmandatory ",(0,t.jsx)(n.code,{children:"host"})," header (to select the virtual host to use for the\nconnection). The RabbitMQ adapter allows this to be optional."]}),"\n",(0,t.jsxs)(n.p,{children:["When omitted, the default virtual host (",(0,t.jsx)(n.code,{children:"/"}),") is presumed.\nTo configure a different default virtual host, add a ",(0,t.jsx)(n.code,{children:"default_vhost"}),"\nsection to the ",(0,t.jsx)(n.code,{children:"rabbitmq_stomp"})," application configuration, e.g."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ini",children:"stomp.default_vhost = /\n"})}),"\n",(0,t.jsxs)(n.p,{children:["If a ",(0,t.jsx)(n.code,{children:"host"})," header is specified it must be one of the\nvirtual hosts known to the RabbitMQ server, otherwise the connection is\nrejected. The ",(0,t.jsx)(n.code,{children:"host"})," header is respected even if the STOMP 1.0 version is\nnegotiated at the time of the connect."]}),"\n",(0,t.jsx)(n.h3,{id:"pear.mp",children:"Message Persistence"}),"\n",(0,t.jsxs)(n.p,{children:["On the ",(0,t.jsx)(n.code,{children:"SEND"})," frame, the STOMP adapter supports the inclusion of a ",(0,t.jsx)(n.code,{children:"persistent"})," header."]}),"\n",(0,t.jsxs)(n.p,{children:["Setting the ",(0,t.jsx)(n.code,{children:"persistent"})," header to ",(0,t.jsx)(n.code,{children:"true"})," has the effect of making the message persistent."]}),"\n",(0,t.jsxs)(n.p,{children:["Receipts for ",(0,t.jsx)(n.code,{children:"SEND"})," frames with ",(0,t.jsx)(n.code,{children:"persistent:true"})," are not sent until a\nconfirm is received from the broker. The exact semantics for c
1onfirms\non persistent messages can be found ",(0,t.jsx)(n.a,{href:"./confirms",children:"here"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"MESSAGE"})," frames for persistent messages will contain a ",(0,t.jsx)(n.code,{children:"persistent:true"}),"\nheader."]}),"\n",(0,t.jsx)(n.h3,{id:"ack-nack",children:"ACK and NACK"}),"\n",(0,t.jsxs)(n.p,{children:["RabbitMQ STOMP plugin supports ",(0,t.jsx)(n.code,{children:"auto"}),", ",(0,t.jsx)(n.code,{children:"client"}),", and ",(0,t.jsx)(n.code,{children:"client-individual"}),"\nsubscription headers that affect how ",(0,t.jsx)(n.code,{children:"ACK"})," on ",(0,t.jsx)(n.code,{children:"NACK"})," operations work."]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"auto"})," mode uses automatic acknowledgements. The ",(0,t.jsx)(n.code,{children:"client"})," mode is manual\n(client-driven) acknowledgements of multiple messages at once. The ",(0,t.jsx)(n.code,{children:"client-individual"}),"\nis for message-by-message manual acknowledgement."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"NACK"})," frames can optionally carry the ",(0,t.jsx)(n.code,{children:"requeue"})," header which controls whether\nthe message will be requeued or discarded/dead lettered. Default value is ",(0,t.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"pear.p",children:"Prefetch"}),"\n",(0,t.jsxs)(n.p,{children:["The prefetch count for all subscriptions is set to unlimited by\ndefault. This can be controlled by setting the ",(0,t.jsx)(n.code,{children:"prefetch-count"})," header\non ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames to the desired integer count."]}),"\n",(0,t.jsx)(n.h3,{id:"stream-support",children:"Stream Support"}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frame supports a ",(0,t.jsx)(n.code,{children:"x-stream-offset"})," header to specify the offset\nto start consuming from in a ",(0,t.jsx)(n.a,{href:"./streams",children:"stream"}),". A typical subscription frame\nfor a stream will look like the following:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"SUBSCRIBE\ndestination:/amq/queue/my-stream\nack:client\nprefetch-count:10\nx-stream-offset:next\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Note the ",(0,t.jsx)(n.code,{children:"ack"})," and ",(0,t.jsx)(n.code,{children:"prefetch-count"})," headers are also necessary. The ",(0,t.jsx)(n.code,{children:"x-stream-offset"})," header\nhas the same semantics as in ",(0,t.jsx)(n.a,{href:"./streams#consuming",children:"AMQP 0.9.1"}),", the possible values are:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"first"})," to start consuming from the first available message in the stream"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"last"})," to start consuming from the last written chunk of messages"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"next"})," to start consuming from the end of the stream (note the consumer will not receive\nmessages until someone is publishing to the stream)"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"offset=<offset-value>"})," to start from a specific offset, e.g. ",(0,t.jsx)(n.code,{children:"offset=40000"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"timestamp=<unix-time>"})," to start from a given time, e.g. ",(0,t.jsx)(n.code,{children:"timestamp=1619432061"})," for\n",(0,t.jsx)(n.code,{children:"2021-04-26T10:14:21+00:00"})]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["The default value is ",(0,t.jsx)(n.code,{children:"next"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["When delivering messages from a stream, the message offset (that is the position of the\nmessage in the stream) is included in the ",(0,t.jsx)(n.code,{children:"x-stream-offset"})," header of the ",(0,t.jsx)(n.code,{children:"MESSAGE"})," frame."]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"/blog/2023/10/16/stream-filtering",children:"Stream filtering"})," is also supported.\nThe ",(0,t.jsx)(n.a,{href:"./stream",children:"stream protocol"})," is the preferred way to interact with streams, but most features are also available with other protocols.\nStream filtering is no exception, it works the same way with STOMP as with ",(0,t.jsx)(n.a,{href:"/blog/2023/10/24/stream-filtering-internals#bonus-stream-filtering-on-amqp",children:"AMQP"}),":"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Declaration: a stream can be created on subscription.\nSet the ",(0,t.jsx)(n.code,{children:"x-queue-type"})," header to ",(0,t.jsx)(n.code,{children:"stream"})," and use the ",(0,t.jsx)(n.code,{children:"x-stream-filter-size-bytes"})," header to set the filter size (optional)."]}),"\n",(0,t.jsxs)(n.li,{children:["Publishing: use the ",(0,t.jsx)(n.code,{children:"x-stream-filter-value"})," header to set the filter value for outbound messages."]}),"\n",(0,t.jsxs)(n.li,{children:["Consuming: use the ",(0,t.jsx)(n.code,{children:"x-stream-filter"})," header to set the expected filter value(s) (use a comma to separate values) and optionally the ",(0,t.jsx)(n.code,{children:"x-stream-match-unfiltered"})," header (",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),") to receive messages without any filter value as well (default is ",(0,t.jsx)(n.code,{children:"false"}),").\nApplications must also implement client-side filtering, as it is still possible to re
1ceive messages that do not meet the filter value(s) criteria."]}),"\n"]}),"\n",(0,t.jsxs)(n.h3,{id:"pear.hpos",children:["Header prohibited on ",(0,t.jsx)(n.code,{children:"SEND"})]}),"\n",(0,t.jsxs)(n.p,{children:["It is not permitted to set a ",(0,t.jsx)(n.code,{children:"message-id"})," header on a ",(0,t.jsx)(n.code,{children:"SEND"})," frame.\nThe header and its value is set by the server on a ",(0,t.jsx)(n.code,{children:"MESSAGE"})," frame sent\nto a client."]}),"\n",(0,t.jsx)(n.h3,{id:"pear.ap",children:"Queue Properties"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"SEND"})," frames also allow headers corresponding to the ",(0,t.jsx)(n.em,{children:"AMQP properties"}),"\navailable when publishing messages. These headers are also set on\n",(0,t.jsx)(n.code,{children:"MESSAGE"})," frames sent to clients."]}),"\n",(0,t.jsxs)(n.p,{children:["All non-deprecated AMQP 0-9-1 properties (",(0,t.jsx)(n.code,{children:"content-type"}),",\n",(0,t.jsx)(n.code,{children:"content-encoding"}),", ",(0,t.jsx)(n.code,{children:"headers"}),", ",(0,t.jsx)(n.code,{children:"delivery-mode"}),", ",(0,t.jsx)(n.code,{children:"priority"}),",\n",(0,t.jsx)(n.code,{children:"correlation-id"}),", ",(0,t.jsx)(n.code,{children:"reply-to"}),", ",(0,t.jsx)(n.code,{children:"expiration"}),", ",(0,t.jsx)(n.code,{children:"message-id"}),", ",(0,t.jsx)(n.code,{children:"timestamp"}),",\n",(0,t.jsx)(n.code,{children:"type"}),", ",(0,t.jsx)(n.code,{children:"user-id"})," and ",(0,t.jsx)(n.code,{children:"app-id"}),") are supported. The following special\nrules apply:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"amqp-message-id"})," in STOMP is converted to ",(0,t.jsx)(n.code,{children:"message-id"})," in AMQP, and\nvice-versa."]}),"\n",(0,t.jsxs)(n.li,{children:["The ",(0,t.jsx)(n.code,{children:"reply-to"})," header causes temporary queues to be created (see\n",(0,t.jsx)(n.a,{href:"#d.tqd",children:"Temp Queue Destinations"})," above)."]}),"\n",(0,t.jsx)(n.li,{children:"Some x-prefixed STOMP headers are translated into optional queue arguments\n(see below)."}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"optional-queue-properties",children:"Optional Queue Properties"}),"\n",(0,t.jsxs)(n.p,{children:["With RabbitMQ, ",(0,t.jsx)(n.code,{children:"SEND"})," and ",(0,t.jsx)(n.code,{children:"SUBSCRIBE"})," frames can include a set of headers to configure the queue behaviour,\nfor example, use ",(0,t.jsx)(n.a,{href:"./ttl",children:"TTL"})," or similar extensions."]}),"\n",(0,t.jsx)(n.p,{children:"The list of supported headers is"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./ttl#per-message-ttl-in-publishers",children:"x-message-ttl"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./ttl#queue-ttl",children:"x-expires"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./maxlength",children:"x-max-length"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./maxlength",children:"x-max-length-bytes"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./dlx",children:"x-dead-letter-exchange"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./dlx",children:"x-dead-letter-routing-key"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"./priority",children:"x-max-priority"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"For example, if you want to use priority queues with STOMP, you\ncan SUBSCRIBE (or SEND) with the following header:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"SUBSCRIBE\ndestination:/queue/my-priority-queue\nx-max-priority:5\n"})}),"\n",(0,t.jsx)(n.h3,{id:"queue-immutability",children:"Queue Immutability"}),"\n",(0,t.jsxs)(n.p,{children:["Once a queue is declared, its properties cannot be changed. Optional arguments\ncan be modified with ",(0,t.jsx)(n.a,{href:"./parameters",children:"policies"}),". Otherwise the queue has to be deleted\nand re-declared. This is true for STOMP clients as well as AMQP 0-9-1."]})]})}function h(e={}){let{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},28453(e,n,s){s.d(n,{R:()=>a,x:()=>c});var i=s(96540);let t={},r=i.createContext(t);function a(e){let n=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.