PageSourceSearch

https://www.rabbitmq.com/assets/js/284ccb5f.9ef41b37.js

js rabbitmq.com collected 2026-10-01 06:29:39 UTC 60,675 bytes, 2 lines download raw bytes

1"use strict";(self.webpackChunkrabbitmq_website=self.webpackChunkrabbitmq_website||[]).push([["12417"],{36631(e,s,n){n.r(s),n.d(s,{metadata:()=>i,default:()=>x,frontMatter:()=>o,contentTitle:()=>a,toc:()=>c,assets:()=>h});var i=JSON.parse('{"id":"shovel-dynamic","title":"Configuring Dynamic Shovels","description":"\x3c!--","source":"@site/versioned_docs/version-4.3/shovel-dynamic.md","sourceDirName":".","slug":"/shovel-dynamic","permalink":"/docs/shovel-dynamic","draft":false,"unlisted":false,"editUrl":"https://github.com/rabbitmq/rabbitmq-website/tree/main/versioned_docs/version-4.3/shovel-dynamic.md","tags":[],"version":"4.3","frontMatter":{"title":"Configuring Dynamic Shovels"},"sidebar":"docsSidebar","previous":{"title":"Shovel Plugin","permalink":"/docs/shovel"},"next":{"title":"Static Shovels","permalink":"/docs/shovel-static"}}'),t=n(74848),r=n(28453),l=n(50773),d=n(57250);let o={title:"Configuring Dynamic Shovels"},a="Configuring Dynamic Shovels",h={},c=[{value:"Overview",id:"overview",level:2},{value:"Configuration",id:"configuration",level:2},{value:"Declaring a Dynamic Shovel",id:"declaring",level:2},{value:"Using CLI Tools",id:"using-cli-tools",level:3},{value:"On URIs without Credentials",id:"on-uris-without-credentials",level:3},{value:"Pre-declared Topology",id:"predeclared-topology",level:3},{value:"Using HTTP API",id:"using-http-api",level:3},{value:"Using Management UI",id:"using-management-ui",level:3},{value:"Inspecting Status of Dynamic Shovels",id:"status",level:2},{value:"Using CLI Tools",id:"using-cli-tools-1",level:3},{value:"Using HTTP API",id:"using-http-api-1",level:3},{value:"Using Management UI",id:"using-management-ui-1",level:3},{value:"Restarting a Shovel",id:"restarting",level:2},{value:"Using CLI Tools",id:"using-cli-tools-2",level:3},{value:"Using HTTP API",id:"using-http-api-2",level:3},{value:"Using Management UI",id:"using-management-ui-2",level:3},{value:"Deleting a Shovel",id:"deleting",level:2},{value:"Using CLI Tools",id:"using-cli-tools-3",level:3},{value:"Using HTTP API",id:"using-http-api-3",level:3},{value:"Time-Based Deletion (Shovel TTL)",id:"time-based-deletion",level:3},{value:"AMQP 0-9-1 Shovel Definition Reference",id:"amqp091-reference",level:2},{value:"AMQP 1.0 Shovel Definition Reference",id:"amqp10-reference",level:2},{value:"Local Shovel Definition Reference",id:"local-reference",level:2},{value:"Monitoring Shovels",id:"status",level:2}];function u(e){let s={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.header,{children:(0,t.jsx)(s.h1,{id:"configuring-dynamic-shovels",children:"Configuring Dynamic Shovels"})}),"\n",(0,t.jsx)(s.h2,{id:"overview",children:"Overview"}),"\n",(0,t.jsxs)(s.p,{children:["This guide focuses on dynamically configured shovels. It assumes\nfamiliarity with the key concepts behind the ",(0,t.jsx)(s.a,{href:"./shovel",children:"Shovel plugin"}),"."]}),"\n",(0,t.jsxs)(s.admonition,{type:"tip",children:[(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.a,{href:"./shovel-dynamic",children:"Dynamic shovels"})," is the modern shovel type. When in doubt,\nprefer dynamic shovels."]}),(0,t.jsxs)(s.p,{children:["To make sure that some shovels start after cluster formation, combine\ndynamic shovels with ",(0,t.jsx)(s.a,{href:"./definitions#import-on-boot",children:"definition import on boot"}),"."]})]}),"\n",(0,t.jsxs)(s.p,{children:["Unlike with static shovels, dynamic shovels are configured using ",(0,t.jsx)(s.a,{href:"./parameters",children:"runtime parameters"}),".\nThey can be started and stopped at any time, including programmatically. Dynamic shovels\ncan be used for both transient (one-off) and permanently running workloads."]}),"\n",(0,t.jsxs)(s.p,{children:["Information about dynamic shovels is stored in RabbitMQ's schema database,\nalong with users, permissions, queues, etc. They therefore can be\nexported together with other ",(0,t.jsx)(s.a,{href:"./definitions",children:"schema definitions"})," in combination\nwith the ",(0,t.jsx)(s.a,{href:"#predeclared-top
1ology",children:"pre-declared topology mode"}),"."]}),"\n",(0,t.jsx)(s.h2,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsxs)(s.p,{children:["Dynamic shovels can be defined using ",(0,t.jsx)(s.a,{href:"./management-cli",children:(0,t.jsx)(s.code,{children:"rabbitmqadmin"})}),", ",(0,t.jsx)(s.a,{href:"./cli",children:(0,t.jsx)(s.code,{children:"rabbitmqctl"})}),", through the\n",(0,t.jsx)(s.a,{href:"./management",children:"management HTTP API"}),", or (with the ",(0,t.jsx)(s.code,{children:"rabbitmq_shovel_management"})," plugin ",(0,t.jsx)(s.a,{href:"./plugins",children:"enabled"}),") through\nthe management UI's administrative section."]}),"\n",(0,t.jsxs)(s.p,{children:["A shovel is declared with a definition body, which is a JSON object. Some keys are mandatory, others are optional.\nThey control connection parameters, protocol used, message transfer source and destination,\n",(0,t.jsx)(s.a,{href:"./confirms",children:"data safety"})," protocol features, and more."]}),"\n",(0,t.jsxs)(s.p,{children:["Every shovel belongs to a virtual host. Note that a Shovel can consume from and publish\nto not only a different virtual host but an entirely different cluster, so\nvirtual host selection primarily acts as a way of organising shovels and access to them,\nmuch like with the rest of ",(0,t.jsx)(s.a,{href:"./access-control",children:"permission in RabbitMQ"}),"."]}),"\n",(0,t.jsxs)(s.p,{children:["Every shovel is also named. The name is used to identify shovels when ",(0,t.jsx)(s.a,{href:"#status",children:"inspecting their status"}),",\n",(0,t.jsx)(s.a,{href:"#deleting",children:"deleting them"})," or ",(0,t.jsx)(s.a,{href:"#restarting",children:"restarting them"}),"."]}),"\n",(0,t.jsx)(s.h2,{id:"declaring",children:"Declaring a Dynamic Shovel"}),"\n",(0,t.jsxs)(s.p,{children:["In this example we will set up a dynamic shovel that will move messages from the queue ",(0,t.jsx)(s.code,{children:'"source-queue"'})," in the\nlocal RabbitMQ cluster to the queue ",(0,t.jsx)(s.code,{children:'"target-queue"'})," on a remote RabbitMQ node, using AMQP 0-9-1."]}),"\n",(0,t.jsx)(s.h3,{id:"using-cli-tools",children:"Using CLI Tools"}),"\n",(0,t.jsxs)(s.p,{children:["A shovel can be declared using CLI tools or the ",(0,t.jsx)(s.a,{href:"./http-api-reference",children:"HTTP API"}),"."]}),"\n",(0,t.jsxs)(s.p,{children:["With ",(0,t.jsx)(s.a,{href:"./cli",children:(0,t.jsx)(s.code,{children:"rabbitmqctl"})}),", a shovel is declared using the ",(0,t.jsx)(s.code,{children:"set_parameter"})," command that declares a [runtime parameter] (./parameters).\n",(0,t.jsx)(s.a,{href:"./management-cli",children:(0,t.jsx)(s.code,{children:"rabbitmqadmin"})})," includes dedicated commands for declaring shovels under the\n",(0,t.jsx)(s.code,{children:"shovels"})," group, namedly ",(0,t.jsx)(s.code,{children:"shovels declare_amqp091"})," and ",(0,t.jsx)(s.code,{children:"shovels declare_amqp10"}),"."]}),"\n",(0,t.jsx)(s.p,{children:"Here are examples that declare a dynamic shovel using CLI tools:"}),"\n",(0,t.jsxs)(l.A,{groupId:"examples",children:[(0,t.jsx)(d.A,{value:"rabbitmqctl-bash",label:"rabbitmqctl with bash",default:!0,children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'# my-shovel here is the name of the shovel\nrabbitmqctl set_parameter shovel my-shovel \\\n  \'{"src-protocol": "amqp091", "src-uri": "amqp://", "src-queue": "source-queue", "dest-protocol": "amqp091", "dest-uri": "amqp://remote-server", "dest-queue": "target-queue", "dest-queue-args": {"x-queue-type": "quorum"}}\'\n'})})}),(0,t.jsx)(d.A,{value:"rabbitmqadmin-bash",label:"rabbitmqadmin with bash",children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'# Declare an AMQP 0-9-1 shovel using rabbitmqadmin\nrabbitmqadmin shovels declare_amqp091 --name my-shovel \\\n    --source-uri "amqp://" \\\n    --destination-uri "amqp://remote-server" \\\n    --source-queue "source-queue" \\\n    --destination-queue "target-queue"\n'})})}),(0,t.jsx)(d.A,{value:"rabbitmqctl-PowerShell",label:"rabbitmqctl with PowerShell",children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-PowerShell",children:'rabbitmqctl.bat set_parameter shovel my-shovel ^\n  "{""src-protocol"": ""amqp091"", ""src-uri"":""amqp://localhost"", ""src-queue"": ""source-queue"", ^\n   ""dest-protocol"": ""amqp091"", ""dest-uri"": ""amqp://remote.rabbitmq.local"", ^\n   ""dest-queue"": ""target-queue"", ""dest-queue-args"": {""x-queue-type"": ""quorum""}}"\n'})})}),(0,t.jsx)(d.A,{value:"rabbitmqadmin-PowerShell",label:"rabbitmqadmin.exe with PowerShell",children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-PowerShell",children:'# Declare an AMQP 0-9-1 shovel using rabbitmqadmin\nrabbitmqadmin.exe shovels declare_amqp091 --name my-shovel ^\n    --source-uri "amqp://" ^\n    --destination-uri "amqp://remote-server" ^\n    --source-queue "source-queue" ^\n    --destination-queue "target-queue"\n'})})})]}),"\n",(0,t.jsx)(s.p,{children:"Here are some examples that declare AMQP 1.0 shovels:"}),"\n",(0,t.jsxs)(l.A,{groupId:"examples",children:[(0,t.jsx)(d.A,{value:"rabbitmqctl-bash",label:"rabbitmqctl with bash",default:!0,children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'# AMQP 1.0 shovel using rabbitmqctl set_parameter\nrabbitmqctl set_parameter shovel my-amqp10-shovel \\\n  \'{"src-protocol": "amqp10", "src-uri": "amqp://username:password@source-server", "src-address": "/queues/source-queue", "dest-protocol": "amqp10", "dest-uri": "amqp://username:password@dest-server", "dest-address": "/queues/target-queue"}\'\n'})})}),(0,t.jsx)(d.A,{value:"rabbitmqadmin-bash",label:"rabbitmqadmin with bash",children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'# Declare an AMQP 1.0 shovel using rabbitmqadmin\nrabbitmqadmin shovels declare_amqp10 --name my-amqp10-shovel \\\n    --source-uri "amqp://username:password@source-server" \\\n    --destination-uri "amqp://username:password@dest-server" \\\n    --source-address "/queues/source-queue" \\\n    --destination-address "/queues/target-queue"\n'})})}),(0,t.jsx)(d.A,{value:"rabbitmqctl-PowerShell",label:"rabbitmqctl with PowerShell",children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-PowerShell",children:'# AMQP 1.0 shovel using rabbitmqctl set_parameter\nrabbitmqctl.bat set_parameter shovel my-amqp10-shovel ^\n  "{""src-protocol"": ""amqp10"", ""src-uri"": ""amqp://username:password@source-server"", ""src-address"": ""/queues/source-queue"", ""dest-protocol"": ""amqp10"", ""dest-uri"": ""amqp://username:password@dest-server"", ""dest-address"": ""/queues/target-queue""}"\n'})})}),(0,t.jsx)(d.A,{value:"rabbitmqadmin-PowerShell",label:"rabbitmqadmin.exe with PowerShell",children:(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-PowerShell",children:'# Declare an AMQP 1.0 shovel using rabbitmqadmin\nrabbitmqadmin.exe shovels declare_amqp10 --name my-amqp10-shovel ^\n    --source-uri "amqp://username:password@source-server" ^\n    --destination-uri "amqp://username:password@dest-server" ^\n    --source-address "/queues/source-queue" ^\n    --destination-address "/queues/target-queue"\n'})})})]}),"\n",(0,t.jsxs)(s.p,{children:["The ",(0,t.jsx)(s.a,{href:"./parameters",children:"runtime parameter"})," definition (body) in these examples includes a few keys:"]}),"\n",(0,t.jsxs)("table",{children:[(0,t.jsx)("caption",{children:"Essential Dynamic Shovel Definition Settings"}),(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Key"})}),(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Description"})})]})}),(0,t.jsxs)("tbody",{children:[(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-uri"}),(0,t.jsxs)("td",{children:[(0,t.jsxs)("div",{children:[(0,t.jsxs)(s.p,{children:["Source connection URI. Mandatory. See\nthe ",(0,t.jsx)("a",{href:"./uri-spec",children:"AMQP URI reference"})," for\ninformation on how RabbitMQ treats AMQP URIs in general."]}),(0,t.jsxs)("dl",{children:[(0,t.jsx)("dt",{children:(0,t.jsxs)(s.p,{children:[(0,t.jsx)("code",{children:"cacertfile"}),", ",(0,t.jsx)("code",{children:"certfile"}),", ",(0,t.jsx)("code",{children:"keyfile"})]})}),(0,t.jsx)("dd",{children:(0,t.jsxs)(s.p,{children:["Client TLS certificate and private key paths.\nSee the ",(0,t.jsx)("a",{href:"./ssl",children:"TLS guide"})," for details.\nOnly of use when URI scheme is ",(0,t.jsx)("code",{children:"amqps"}),"."]})}),(0,t.jsx)("dt",{children:(0,t.jsxs)(s.p,{children:[(0,t.jsx)("code",{children:"verify"}),", ",(0,t.jsx)("code",{children:"fail_if_no_peer_cert"})]})}),(0,t.jsxs)("dd",{children:[(0,t.jsxs)(s.p,{children:["Use to enable or disable peer verification of the server's TLS certificate.\nSee ",(0,t.jsx)("a",{href:"./shovel#tls",children:"Securing Shovel Connections with TLS"})," and the general ",(0,t.jsx)("a",{href:"./ssl#peer-verification",children:"TLS guide"})," to learn more.\nOnly of use when URI scheme is ",(0,t.jsx)("code",{children:"amqps"}),"."]}),(0,t.jsx)("div",{children:(0,t.jsx)(s.admonition,{type:"important",children:(0,t.jsx)(s.p,{children:"Note that starting with Erlang 26, peer verification for TLS clients (such as shovels)\nis enabled by default."})})})]})]})]}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The value of this parameter can either be a string, or a list of\
1nstrings. If more than one string is provided, the shovel will\nrandomly pick ",(0,t.jsx)("strong",{children:"one"})," URI from the list until\none of the endpoints succeeds."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-protocol"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Protocol to use when connecting to the source.\nEither ",(0,t.jsx)("code",{children:"amqp091"}),", ",(0,t.jsx)("code",{children:"amqp10"})," or ",(0,t.jsx)("code",{children:"local"}),". If omitted it will default to ",(0,t.jsx)("code",{children:"amqp091"}),".\nSee protocol specific properties below."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-queue"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Source queue that the shovel will consume from.\nThe queue from which to consume. Either this\nor ",(0,t.jsx)("code",{children:"src-exchange"})," (but not both) must be set."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If the source queue does not exist on the target virtual host, and ",(0,t.jsx)("code",{children:"src-queue-args"}),"\nparameter was not provided, shovel will declare a classic durable queue with no optional arguments."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Shovels can use a pre-declared topology instead of declaring the source.\nSee the ",(0,t.jsx)(s.a,{href:"#predeclared-topology",children:"Predeclared topology"})," section below."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-queue-args"}),(0,t.jsx)("td",{children:(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Optional arguments for ",(0,t.jsx)("code",{children:"src-queue"})," declaration, eg. the queue type."]})})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-consumer-name"}),(0,t.jsx)("td",{children:(0,t.jsxs)("div",{children:[(0,t.jsxs)(s.p,{children:["Optional consumer name. This value is used as the ",(0,t.jsx)(s.a,{href:"./consumers#consumer-tags",children:"consumer tag"}),"\nwhen ",(0,t.jsx)(s.code,{children:"src-protocol"})," is set to ",(0,t.jsx)(s.code,{children:"amqp091"})," or ",(0,t.jsx)(s.code,{children:"local"})," and as the link name when ",(0,t.jsx)(s.code,{children:"src-protocol"}),"\nis ",(0,t.jsx)(s.code,{children:"amqp10"}),"."]}),(0,t.jsx)(s.p,{children:"If not specified, a random value is used."})]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-uri"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Same as ",(0,t.jsx)("code",{children:"src-uri"})," above but for destination connection."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-protocol"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Protocol to use when connecting to the destination.\nEither ",(0,t.jsx)("code",{children:"amqp091"})," or ",(0,t.jsx)("code",{children:"amqp10"}),".\nIf omitted it will default to ",(0,t.jsx)("code",{children:"amqp091"}),".\nSee protocol specific properties below."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-queue"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The queue to which messages should be published. Either this\nor ",(0,t.jsx)("code",{children:"dest-exchange"})," (but not both) may be set. If\nneither is set then messages are republished with their original\nexchange and routing key."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If the destination queue does not exist in the destination virtual host,\nand ",(0,t.jsx)("code",{children:"dest-queue-args"})," parameter was not provided,\nshovel will declare a classic durable queue with no optional arguments."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Shovels can use a pre-declared topology instead of declaring the destination.\nSee the ",(0,t.jsx)(s.a,{href:"#predeclared-topology",children:"Predeclared topology"})," section below."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-queue-args"}),(0,t.jsx)("td",{children:(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Optional arguments for ",(0,t.jsx)("code",{children:"dest-queue"})," declaration, eg. the queue type."]})})})]})]})]}),"\n",(0,t.jsx)(s.p,{children:"There are other Shovel definition keys that will be covered later in this guide."}),"\n",(0,t.jsx)(s.h3,{id:"on-uris-without-credentials",children:"On URIs without Credentials"}),"\n",(0,t.jsxs)(s.p,{children:["A URI that does not include credentials connects as the default user (",(0,t.jsx)("code",{children:"guest"}),"),\nwhose connectivity is ",(0,t.jsxs)("a",{href:"./access-control#loopback-users",children:["restricted to ",(0,t.jsx)(s.code,{children:"localhost"})]}),"."]}),"\n",(0,t.jsxs)(s.p,{children:["In production environments, the default user ",(0,t.jsx)("a",{href:"./production-checklist#users",children:"should use a generated username and password"}),",\nor deleted entirely in favor of a manually created user."]}
1),"\n",(0,t.jsx)(s.h3,{id:"predeclared-topology",children:"Pre-declared Topology"}),"\n",(0,t.jsx)(s.p,{children:"Shovels can use a pre-declared topology instead of declaring its source and destination."}),"\n",(0,t.jsxs)(s.p,{children:["For example, this may be necessary when the topology is ",(0,t.jsx)(s.a,{href:"./definitions#import-on-boot",children:"imported from a definitions file at boot time"}),".\nUsing a pre-declared topology avoids a chicken-and-egg problem between the import of definitions and\nShovel plugin startup: the plugin must be enabled for definitions to pass validation (of the runtime parameters part)."]}),"\n",(0,t.jsxs)(s.p,{children:["Here is how the plugin can be configured to wait until the source is available ",(0,t.jsxs)(s.a,{href:"./configure",children:["using ",(0,t.jsx)(s.code,{children:"rabbitmq.conf"})]}),":"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"# all shovels started on this node will use pre-declared topology\nshovel.topology.predeclared = true\n"})}),"\n",(0,t.jsx)(s.p,{children:"If only some shovels need to use a pre-declared topology, the same behavior can be configured\nfor specific shovels using the following shovel properties:"}),"\n",(0,t.jsxs)("table",{class:"name-description",children:[(0,t.jsx)("caption",{children:"Additional Dynamic Shovel Definition Settings"}),(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Key"})}),(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Description"})})]})}),(0,t.jsxs)("tbody",{children:[(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-predeclared"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["When set to ",(0,t.jsx)("code",{children:"true"}),", the plugin waits until ",(0,t.jsx)("code",{children:"src-queue"})," is available\ninstead of declaring the topology itself using ",(0,t.jsx)("code",{children:"src-queue-args"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-predeclared"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["When set to ",(0,t.jsx)("code",{children:"true"}),", the plugin waits until ",(0,t.jsx)("code",{children:"dest-queue"})," is available\ninstead of declaring the topology itself using ",(0,t.jsx)("code",{children:"dest-queue-args"}),"."]})})]})]})]}),"\n",(0,t.jsx)(s.h3,{id:"using-http-api",children:"Using HTTP API"}),"\n",(0,t.jsxs)(s.p,{children:["To declare a shovel using the HTTP API, make sure that the ",(0,t.jsx)(s.a,{href:"./management",children:"management"})," plugin\nis enabled, then use the following endpoint:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"PUT /api/parameters/shovel/{vhost}/{name}\n"})}),"\n",(0,t.jsxs)(s.p,{children:["where ",(0,t.jsx)(s.code,{children:"{vhost}"})," is the virtual host in which the Shovel should be started and ",(0,t.jsx)(s.code,{children:"{name}"}),"\nis the name of the new shovel. The endpoint requires that the user that invokes it\nhas ",(0,t.jsx)(s.code,{children:"policymaker"})," privileges (tag)."]}),"\n",(0,t.jsx)(s.p,{children:"The request body is a JSON document similar in structure to that described earlier in this guide:"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:'{\n  "value": {\n    "src-protocol": "amqp091",\n    "src-uri":  "amqp://localhost",\n    "src-queue":  "source-queue",\n    "dest-protocol": "amqp091",\n    "dest-uri": "amqp://remote.rabbitmq.local",\n    "dest-queue": "destination-queue"\n  }\n}\n'})}),"\n",(0,t.jsxs)(s.p,{children:["Below is an example that uses ",(0,t.jsx)(s.code,{children:"curl"})," to declare a shovel on a local node using\n",(0,t.jsx)(s.a,{href:"./access-control#default-state",children:"default user credentials"}),". The shovel will\ntransfer messages between two queues, ",(0,t.jsx)(s.code,{children:'"source-queue"'})," and ",(0,t.jsx)(s.code,{children:'"destination-queue"'}),", in the default virtual host."]}),"\n",(0,t.jsxs)(s.p,{children:["Note that this exact command would fail if invoked against\na remote node. Please ",(0,t.jsx)(s.a,{href:"./access-control",children:"add a new user"})," tagged as ",(0,t.jsx)(s.code,{children:"policymaker"}),"\nfor your own experiments."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'# Note: this user\'s access is limited to localhost!\ncurl -v -u guest:guest -X PUT http://localhost:15672/api/parameters/shovel/%2f/my-shovel \\\n                       -H "content-type: application/json" \\\n                       -d @- <<EOF\n{\n  "value": {\n    "src-protocol": "amqp091",\n    "src-uri": "amqp://localhost",\n    "src-queue": "source-queue",\n    "dest-protocol": "amqp091",\n    "dest-uri": "amqp://localhost",\n    "dest-queue": "destination-queue"\n  }\n}\nEOF\n'})}),"\n",(0,t.jsx)(s.h3,{id:"using-management-ui",children:"Using Management UI"}),"\n",(0,t.jsxs)(s.p,{children:["To declare a shovel using the management UI, first make sure that the ",(0,t.jsx)(s.a,{href:"./management",children:"management"})," plugin\nis enabled."]}
1),"\n",(0,t.jsx)(s.p,{children:"Then"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Navigate to ",(0,t.jsx)(s.code,{children:"Admin"})," > ",(0,t.jsx)(s.code,{children:"Shovel Management"})," > ",(0,t.jsx)(s.code,{children:"Add a new shovel"})]}),"\n",(0,t.jsx)(s.li,{children:"Fill out the form with shovel parameters covered earlier in this guide"}),"\n",(0,t.jsx)(s.li,{children:"Click Add shovel"}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"status",children:"Inspecting Status of Dynamic Shovels"}),"\n",(0,t.jsx)(s.h3,{id:"using-cli-tools-1",children:"Using CLI Tools"}),"\n",(0,t.jsxs)(s.p,{children:["Use ",(0,t.jsx)(s.code,{children:"rabbitmqctl shovel_status"})," to inspect dynamic shovels in a cluster. The ",(0,t.jsx)(s.code,{children:"rabbitmq_shovel"}),"\nplugin must be enabled on the host where this command is executed."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:"rabbitmqctl shovel_status --formatter=pretty_table\n"})}),"\n",(0,t.jsxs)(s.p,{children:["The output can be formatted as JSON and redirected to a tool such as ",(0,t.jsx)(s.a,{href:"https://stedolan.github.io/jq/",children:(0,t.jsx)(s.code,{children:"jq"})}),":"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:"rabbitmqctl shovel_status --formatter=json | jq\n"})}),"\n",(0,t.jsx)(s.h3,{id:"using-http-api-1",children:"Using HTTP API"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"GET /api/shovels"})," is an endpoint that can be used to list dynamic\nshovels in a cluster. The endpoint is provided by the ",(0,t.jsx)(s.code,{children:"rabbitmq_shovel_management"})," plugin\nwhich must be enabled on the target node."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"# Note: this user's access is limited to localhost!\n curl -v -u guest:guest -X GET http://localhost:15672/api/shovels/\n"})}),"\n",(0,t.jsxs)(s.p,{children:["To inspect shovels in a specific virtual host, use ",(0,t.jsx)(s.code,{children:"GET /api/shovels/{vhost}"}),"\n",(0,t.jsx)(s.code,{children:"{vhost}"})," is the virtual host name. The value must be percent-encoded."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"# Note: this user's access is limited to localhost!\n curl -v -u guest:guest -X GET http://localhost:15672/api/shovels/%2f\n"})}),"\n",(0,t.jsxs)(s.p,{children:["To inspect status of a specific shovels, use ",(0,t.jsx)(s.code,{children:"GET /api/shovels/vhost/{vhost}/{name}"}),"\n",(0,t.jsx)(s.code,{children:"{vhost}"})," is the virtual host in which the Shovel is running and ",(0,t.jsx)(s.code,{children:"{name}"}),"\nis the name of the shovel.  Both values must be percent-encoded."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"# Note: this user's access is limited to localhost!\n curl -v -u guest:guest -X GET http://localhost:15672/api/shovels/vhost/%2f/my-shovel\n"})}),"\n",(0,t.jsx)(s.h3,{id:"using-management-ui-1",children:"Using Management UI"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Navigate to ",(0,t.jsx)(s.code,{children:"Admin"})," > ",(0,t.jsx)(s.code,{children:"Shovel Status"})]}),"\n",(0,t.jsx)(s.li,{children:"Locate the shovel of interest in the table"}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"restarting",children:"Restarting a Shovel"}),"\n",(0,t.jsxs)(s.p,{children:["A dynamic Shovel can be restarted. Restarting a shovel briefly interrupts its operations\nand makes it reconnect to both source and destination. When an appropriate ",(0,t.jsx)(s.a,{href:"./confirms",children:"acknowledgement mode"}),' is\nused by a shovel, the interruption is safe: any unacknowledged or unconfirmed ("in flight") messages\nconsumed from the source or published to the destination will be automatically requeued\nwhen the shovel is stopped, and consumed again after the restart.']}),"\n",(0,t.jsx)(s.h3,{id:"using-cli-tools-2",children:"Using CLI Tools"}),"\n",(0,t.jsxs)(s.p,{children:["Use ",(0,t.jsx)(s.code,{children:"rabbitmqctl restart_shovel"})," to restart a shovel using its name. The ",(0,t.jsx)(s.code,{children:"rabbitmq_shovel"}),"\nplugin must be enabled on the host where this command is executed."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'rabbitmqctl restart_shovel "my-shovel"\n'})}),"\n",(0,t.jsx)(s.h3,{id:"using-http-api-2",children:"Using HTTP API"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"DELETE /api/shovels/vhost/{vhost}/{name}/restart"})," is an endpoint that restarts\na dynamic shovel. The endpoint is provided by the ",(0,t.jsx)(s.code,{children:"rabbitmq_shovel_management"})," plugin\nwhich must be enabled on the target node."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"{vhost}"})," is the virtual host in which the Shovel is running and ",(0,t.jsx)(s.code,{children:"{name}"}),"\nis the name of the shovel to be restarted.  Both values must be percent-encoded."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"# Note: this user's access is limited to localhost!\n curl -v -u guest:guest -X DELETE http://localhost:15672/api/shovels/vhost/%2f/my-shovel/restart\n"})}),"\n",(0,t.jsx)(s.h3,{id:"using-management-ui-2",children:"Using Management UI"}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Navigate to ",(0,t.jsx)(s.code,{children:"Admin"})," > ",(0,t.jsx)(s.code,{children:"Shovel Status"})]}),"\n",(0,t.jsx)(s.li,{children:"Locate the shovel of interest in the table"}),"\n",(0,t.jsx)(s.li,{children:"Click Restart and wait for the next UI refresh"}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"deleting",children:"Deleting a Shovel"}),"\n",(0,t.jsx)(s.h3,{id:"using-cli-tools-3",children:"Using CLI Tools"}),"\n",(0,t.jsxs)(s.p,{children:["To delete a Shovel using CLI tools, use ",(0,t.jsx)(s.code,{children:"rabbitmqctl clear_parameter"})," and pass ",(0,t.jsx)(s.code,{children:"shovel"})," for\ncomponent name and the name of the shovel that should be deleted:"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:'rabbitmqctl clear_parameter shovel "my-shovel"\n'})}),"\n",(0,t.jsx)(s.h3,{id:"using-http-api-3",children:"Using HTTP API"}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"DELETE /api/parameters/shovel/{vhost}/{name}"})," is the endpoint that can be used\nto delete a shovel."]}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"{vhost}"})," is the virtual host in which the Shovel is running and ",(0,t.jsx)(s.code,{children:"{name}"}),"\nis the name of the shovel to be deleted. Both values must be percent-encoded."]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-bash",children:"# Note: this user's access is limited to localhost!\ncurl -v -u guest:guest -X DELETE http://localhost:15672/api/parameters/shovel/%2f/my-shovel\n"})}),"\n",(0,t.jsx)(s.h3,{id:"time-based-deletion",children:"Time-Based Deletion (Shovel TTL)"}),"\n",(0,t.jsxs)(s.p,{children:["A dynamic shovel can be given a time-to-live using the optional\n",(0,t.jsx)(s.code,{children:"src-delete-after-duration"})," source setting, a positive integer in seconds.\nWhen time is up, the shovel stops, regardless of how many\nmessages it has transferred by that point. AMQP 0-9-1, AMQP 1.0 and local\nshovels all support this setting."]}),"\n",(0,t.jsx)(s.p,{children:"The countdown starts when the shovel connects to its source, and restarts\nif the shovel reconnects, for example, after a node restart or a network failure."}),"\n",(0,t.jsxs)(s.p,{children:[(0,t.jsx)(s.code,{children:"src-delete-after-duration"}
1)," is independent of ",(0,t.jsx)(s.a,{href:"#amqp091-reference",children:(0,t.jsx)(s.code,{children:"src-delete-after"})}),",\nwhich deletes a shovel after a certain number of messages have been transferred.\nWhen both are set, the condition reached first deletes the shovel."]}),"\n",(0,t.jsxs)(s.p,{children:["The value has a configurable minimum, 60 seconds by default. Values below the\nminimum are automatically increased to it, and a warning is logged.\nThe minimum can be adjusted using ",(0,t.jsx)(s.code,{children:"shovel.delete_after_duration_floor"})," key in\n",(0,t.jsx)(s.code,{children:"rabbitmq.conf"}),":"]}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-ini",children:"# lowers the src-delete-after-duration minimum to 30 seconds\nshovel.delete_after_duration_floor = 30\n"})}),"\n",(0,t.jsx)(s.p,{children:"The minimum cannot be set below 15 seconds to discourage very short-lived shovels\nand thus expensive shovel churn."}),"\n",(0,t.jsx)(s.h2,{id:"amqp091-reference",children:"AMQP 0-9-1 Shovel Definition Reference"}),"\n",(0,t.jsx)(s.p,{children:"There are several Shovel properties that haven't been covered in the above example.\nThey don't change how dynamic shovels work fundamentally, and do not change\nthe declaration process."}),"\n",(0,t.jsxs)("table",{children:[(0,t.jsx)("caption",{children:"Optional Dynamic Shovel Definition Settings (AMQP 0-9-1)"}),(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Key"})}),(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Description"})})]})}),(0,t.jsxs)("tbody",{children:[(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"reconnect-delay"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"The duration (in seconds) to wait before reconnecting to the\nbrokers after being disconnected at either end. Default is 1."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"ack-mode"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Determines how the shovel should ",(0,t.jsx)("a",{href:"./confirms",children:"acknowledge"})," consumed messages.\nValid values are ",(0,t.jsx)("code",{children:"on-confirm"}),", ",(0,t.jsx)("code",{children:"on-publish"}),", and ",(0,t.jsx)("code",{children:"no-ack"}),".\n",(0,t.jsx)("code",{children:"on-confirm"})," is used by default."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"on-confirm"})," (the default), messages are\n",(0,t.jsx)("a",{href:"./confirms",children:"acknowledged"})," to the source broker after they have been confirmed\nby the destination. This handles network errors and broker\nfailures without losing messages, and is the slowest option."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"on-publish"}),", messages are ",(0,t.jsx)("a",{href:"./confirms",children:"acknowledged"})," to\nthe source broker after they have been published at the\ndestination (but not yet confirmed). Messages may be lost in the event of network or broker failures."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"no-ack"}),", ",(0,t.jsx)("a",{href:"./confirms",children:"automatic message acknowledgements"})," will be used.\nThis option will offer the highest throughput but is not safe (will lose messages in the event of network or broker failures)."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-delete-after"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"Determines when (if ever) the shovel should delete\nitself. This can be useful if the shovel is being treated\nas more of a move operation - i.e. being used to move\nmessages from one queue to another on an ad hoc basis."})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The default is ",(0,t.jsx)("code",{children:"never"}),", meaning the\nshovel should never delete itself."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"queue-length"})," then the shovel will\nmeasure the length of the source queue when starting up,\nand delete itself after it has transferred that many\nmessages."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to an integer, then the shovel will transfer that\nnumber of messages before deleting itself. This option cannot\nbe used together with ",(0,t.jsx)("code",{children:"ack-mode"})," set to ",(0,t.jsx)("code",{children:"no-ack"}),"."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-delete-after-duration"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["A time-to-live for the shovel, in seconds. When the time is up,\nthe shovel will delete itself. See\n",(0,t.jsx)("a",{href:"#time-based-deletion",children:"Time-Based Deletion"}),"."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"Values below a configurable minimum (60 seconds by default) are\nautomatically increased to it."})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-prefetch-count"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["The maximum number of unacknowledged messages copied over a shovel at\nany one time. Default is ",(0,t.jsx)("code",{children:"1000"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-exchange"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The exchange from which to consume. Either this\nor ",(0,t.jsx)("code",{children:"src-queue"})," (but not both) must be set."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The shovel will declare an exclusive queue and bind it to the\nnamed exchange with ",(0,t.jsx)("code",{children:"src-exchange-key"})," before consuming\nfrom the queue."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"If the source exchange does not exist on the source broker, it\nwill be not declared; the shovel will fail to start."})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-exchange-key"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Routing key when using ",(0,t.jsx)("code",{children:"src-exchange"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-consumer-args"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Consumer arguments, such as ",(0,t.jsx)(s.code,{children:"x-single-active-consumer"})," or ",(0,t.jsx)(s.code,{children:"x-stream-offset"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-exchange"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The exchange to which messages should be published. Either this\nor ",(0,t.jsx)("code",{children:"dest-queue"})," (but not both) may be set."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"If the destination exchange does not exist on the destination broker,\nit will be not declared; the shovel will fail to start."})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-exchange-key"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Routing key when using ",(0,t.jsx)("code",{children:"dest-exchange"}),". If this is not\nset, the original message's routing key will be used."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-publish-properties"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["A map (JSON object) of properties to overwrite when shovelling messages. Setting\nheaders this way is not currently supported. Default is ",(0,t.jsx)("code",{}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-add-forward-headers"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Whether to add ",(0,t.jsx)("code",{children:"x-shovelled"})," headers to the\nshovelled messages indicating where they have been shovelled\nfrom and to. Default is false."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-add-timestamp-
1header"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Whether to add ",(0,t.jsx)("code",{children:"x-shovelled-timestamp"})," headers to the\nshovelled messages  containing timestamp (in seconds since epoch)\nwhen message had been shovelled. Default is false."]})})]})]})]}),"\n",(0,t.jsx)(s.h2,{id:"amqp10-reference",children:"AMQP 1.0 Shovel Definition Reference"}),"\n",(0,t.jsx)(s.p,{children:"AMQP 1.0 source and destination properties have some differences from their AMQP 0-9-1\ncounterparts."}),"\n",(0,t.jsxs)("table",{children:[(0,t.jsx)("caption",{children:"Optional Dynamic Shovel Definition Settings (AMQP 1.0)"}),(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Key"})}),(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Description"})})]})}),(0,t.jsxs)("tbody",{children:[(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-uri"}),(0,t.jsxs)("td",{children:[(0,t.jsxs)(s.p,{children:["The AMQP URI for the source. Mandatory. AMQP 1.0 URIs implement\nas subset of what is described in the ",(0,t.jsx)("a",{href:"./uri-spec",children:"AMQP URI reference"}),".\nThere is no ",(0,t.jsx)("a",{href:"./vhosts",children:"virtual host"})," concept in AMQP 1.0, so URI path\nsegments are not supported. The set of query parameters it supports are different from AMQP 0.9.1\nURI(s):"]}),(0,t.jsxs)("dl",{children:[(0,t.jsx)("dt",{children:(0,t.jsx)("code",{children:"idle_time_out"})}),(0,t.jsx)("dd",{children:"heartbeat interval"}),(0,t.jsx)("dt",{children:(0,t.jsx)("code",{children:"hostname"})}),(0,t.jsxs)("dd",{children:[(0,t.jsx)(s.p,{children:"This field indicates the  connection target. What exactly that means depends on the target AMQP 1.0 broker."}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"For example, Azure ServiceBus requires this to be set even if it is the same as the host segment\nin the URI."})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["In the case of RabbitMQ, this field can be used to specify the target ",(0,t.jsx)(s.a,{href:"./vhosts",children:"virtual host"})," in case it is different from the default one.\nTo do so, set this query parameter to ",(0,t.jsx)(s.code,{children:"vhost:{name}"}),", e.g. ",(0,t.jsx)(s.code,{children:"vhost:example-vhost"}),"."]})})]}),(0,t.jsx)("dt",{children:(0,t.jsx)("code",{children:"sasl"})}),(0,t.jsx)("dd",{children:(0,t.jsxs)(s.p,{children:[(0,t.jsx)("code",{children:"anon"}),", ",(0,t.jsx)("code",{children:"none"})," or ",(0,t.jsx)("code",{children:"plain"}),"\nDefaults to: ",(0,t.jsx)("code",{children:"none"}),". When using ",(0,t.jsx)("code",{children:"plain"})," the\nuser and password segments of the URI need to be set."]})}),(0,t.jsx)("dt",{children:(0,t.jsxs)(s.p,{children:[(0,t.jsx)("code",{children:"cacertfile"}),", ",(0,t.jsx)("code",{children:"certfile"}),", ",(0,t.jsx)("code",{children:"keyfile"})]})}),(0,t.jsx)("dd",{children:(0,t.jsxs)(s.p,{children:["Client TLS certificate and private key paths.\nSee the ",(0,t.jsx)("a",{href:"./ssl",children:"TLS guide"})," for details.\nOnly of use when URI scheme is ",(0,t.jsx)("code",{children:"amqps"}),"."]})}),(0,t.jsx)("dt",{children:(0,t.jsxs)(s.p,{children:[(0,t.jsx)("code",{children:"verify"}),", ",(0,t.jsx)("code",{children:"fail_if_no_peer_cert"})]})}),(0,t.jsxs)("dd",{children:[(0,t.jsxs)(s.p,{children:["Use to enable or disable peer verification of the server's TLS certificate.\nSee the ",(0,t.jsx)("a",{href:"./ssl#peer-verification",children:"TLS guide"})," for details.\nOnly of use when URI scheme is ",(0,t.jsx)("code",{children:"amqps"}),"."]}),(0,t.jsx)("div",{children:(0,t.jsx)(s.admonition,{type:"important",children:(0,t.jsx)(s.p,{children:"Note that starting with Erlang 26, peer verification for TLS clients (such as shovels)\nis enabled by default."})})})]})]})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-address"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"The AMQP 1.0 link address. Mandatory."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-address"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"The AMQP 1.0 link address. Mandatory."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-prefetch-count"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["The maximum number of unacknowledged messages copied over a shovel at\nany one time. Default is ",(0,t.jsx)("code",{children:"1000"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-properties"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"Properties to overwrite when shovelling messages.\nSee AMQP 1.0 spec \xa73.2.4 for details of all possible\nproperties."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-application-properties"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"Application properties to set when shovelling messages."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-add-forward-headers"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Whether to add ",(0,t.jsx)("code",{children:"x-shovelled"})," application properties to the\nshovelled messages indicating where they have been shovelled\nfrom and to. Default is false."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-add-timestamp-
1header"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Whether to set the ",(0,t.jsx)("code",{children:"creation_time"})," header to the\ntimestamp (in milliseconds since epoch) of the moment when\nmessage had been republished. Default is false."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"reconnect-delay"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"The duration (in seconds) to wait before reconnecting to the\nbrokers after being disconnected at either end. Default is 1."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"ack-mode"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Determines how the shovel should ",(0,t.jsx)("a",{href:"./confirms",children:"acknowledge"})," consumed messages.\nValid values are ",(0,t.jsx)("code",{children:"on-confirm"}),", ",(0,t.jsx)("code",{children:"on-publish"}),", and ",(0,t.jsx)("code",{children:"no-ack"}),".\n",(0,t.jsx)("code",{children:"on-confirm"})," is used by default."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"on-confirm"})," (the default), messages are\n",(0,t.jsx)("a",{href:"./confirms",children:"acknowledged"})," to the source broker after they have been confirmed\nby the destination. This handles network errors and broker\nfailures without losing messages, and is the slowest option."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"on-publish"}),", messages are ",(0,t.jsx)("a",{href:"./confirms",children:"acknowledged"})," to\nthe source broker after they have been published at the\ndestination (but not yet confirmed). Messages may be lost in the event of network or broker failures."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"no-ack"}),", ",(0,t.jsx)("a",{href:"./confirms",children:"automatic message acknowledgements"})," will be used.\nThis option will offer the highest throughput but is not safe (will lose messages in the event of network or broker failures)."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-delete-after"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"Determines when (if ever) the shovel should delete\nitself. This can be useful if the shovel is being treated\nas more of a move operation - i.e. being used to move\nmessages from one queue to another on an ad hoc basis."})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The default is ",(0,t.jsx)("code",{children:"never"}),", meaning the\nshovel should never delete itself."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to an integer, then the shovel will transfer that\nnumber of messages before deleting itself. This option cannot\nbe used in conjunction with ",(0,t.jsx)("code",{children:"ack-mode"}),": ",(0,t.jsx)("code",{children:"no-ack"}),"."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-delete-after-duration"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["A time-to-live for the shovel, in seconds. When the time is up,\nthe shovel will delete itself. See\n",(0,t.jsx)("a",{href:"#time-based-deletion",children:"Time-Based Deletion"}),"."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"Values below a configurable minimum (60 seconds by default) are\nautomatically increased to it."})})]})]})]})]}),"\n",(0,t.jsx)(s.h2,{id:"local-reference",children:"Local Shovel Definition Reference"}),"\n",(0,t.jsx)(s.p,{children:"There are several Shovel properties that haven't been covered in the above example.\nThey don't change how dynamic shovels work fundamentally, and do not change\nthe declaration process."}),"\n",(0,t.jsxs)("table",{children:[(0,t.jsx)("caption",{children:"Optional Dynamic Shovel Definition Settings (Local)"}),(0,t.jsx)("thead",{children:(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Key"})}),(0,t.jsx)("td",{children:(0,t.jsx)("strong",{children:"Description"})})]})}),(0,t.jsxs)("tbody",{children:[(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"reconnect-delay"}),(0,t.jsx)("td",{children:(0,t.jsx)(s.p,{children:"The duration (in seconds) to wait before reconnecting to the\nbrokers after being disconnected at either end. Default is 1."})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"ack-mode"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["Determines how the shovel should ",(0,t.jsx)("a",{href:"./confirms",children:"acknowledge"})," consumed messages.\nValid values are ",(0,t.jsx)("code",{children:"on-confirm"}),", ",(0,t.jsx)("code",{children:"on-publish"}),", and ",(0,t.jsx)("code",{children:"no-ack"}),".\n",(0,t.jsx)("code",{children:"on-confirm"})," is used by default."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"on-confirm"})," (the default), messages are\n",(0,t.jsx)("a",{href:"./confirms",children:"acknowledged"})," to the source broker after they have been confirmed\nby the destination. This handles network errors and broker\nfailures without losing messages, and is the slowest option."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"on-publish"}),", messages are ",(0,t.jsx)("a",{href:"./confirms",children:"acknowledged"})," to\nthe source broker after they have been published at the\ndestination (but not yet confirmed). Messages may be lost in the event of network or broker failures."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"no-ack"}),", ",(0,t.jsx)("a",{href:"./confirms",children:"automatic message acknowledgements"})," will be used.\nThis option will offer the highest throughput but is not safe (will lose messages in the event of network or broker failures)."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-delete-after"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"Determines when (if ever) the shovel should delete\nitself. This can be useful if the shovel is being treated\nas more of a move operation - i.e. being used to move\nmessages from one queue to another on an ad hoc basis."})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The default is ",(0,t.jsx)("code",{children:"never"}),", meaning the\nshovel should never delete itself."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to ",(0,t.jsx)("code",{children:"queue-length"})," then the shovel will\nmeasure the length of the source queue when starting up,\nand delete itself after it has transferred that many\nmessages."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["If set to an integer, then the shovel will transfer that\nnumber of messages before deleting itself. This option cannot\nbe used in conjunction with ",(0,t.jsx)("code",{children:"ack-mode : no-ack"}),"."]})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-delete-after-duration"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["A time-to-live for the shovel, in seconds. When the interval elapses,\nthe shovel will delete itself. See\n",(0,t.jsx)("a",{href:"#time-based-deletion",children:"Time-Based Deletion"}),"."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"Values below a configurable minimum (60 seconds by default) are\nautomatically increased to it."})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-prefetch-count"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["The maximum number of unacknowledged messages copied over a shovel at\nany one time. Default is ",(0,t.jsx)("code",{children:"1000"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-exchange"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The exchange from which to consume. Either this\nor ",(0,t.jsx)("code",{children:"src-queue"})," (but not both) must be set."]})}),(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The shovel will declare an exclusive queue and bind it to the\nnamed exchange with ",(0,t.jsx)("code",{children:"src-exchange-key"})," before consuming\nfrom the queue."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"If the source exchange does not exist on the source broker, it\nwill be not declared; the shovel will fail to start."})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-exchange-key"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Routing key when using ",(0,t.jsx)("code",{children:"src-exchange"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"src-consumer-args"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Consumer arguments, such as ",(0,t.jsx)(s.code,{children:"x-single-active-consumer"})," or ",(0,t.jsx)(s.code,{children:"x-stream-offset"}),"."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-exchange"}),(0,t.jsxs)("td",{children:[(0,t.jsx)("div",{children:(0,t.jsxs)(s.p,{children:["The exchange to which messages should be published. Either this\nor ",(0,t.jsx)("code",{children:"dest-queue"})," (but not both) may be set."]})}),(0,t.jsx)("div",{children:(0,t.jsx)(s.p,{children:"If the destination exchange does not exist on the destination broker,\nit will be not declared; the shovel will fail to start."})})]})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-exchange-key"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Routing key when using ",(0,t.jsx)("code",{children:"dest-exchange"}),". If this is not\nset, the original message's routing key will be used."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-add-forward-headers"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Whether to add ",(0,t.jsx)("code",{children:"x-opt-shovelled"})," headers to the\nshovelled messages indicating where they have been shovelled\nfrom and to. Default is false."]})})]}),(0,t.jsxs)("tr",{children:[(0,t.jsx)("td",{children:"dest-add-timestamp-
1header"}),(0,t.jsx)("td",{children:(0,t.jsxs)(s.p,{children:["Whether to add ",(0,t.jsx)("code",{children:"x-opt-shovelled-timestamp"})," headers to the\nshovelled messages  containing timestamp (in seconds since epoch)\nwhen message had been shovelled. Default is false."]})})]})]})]}),"\n",(0,t.jsx)(s.h2,{id:"status",children:"Monitoring Shovels"}),"\n",(0,t.jsxs)(s.p,{children:["See ",(0,t.jsx)(s.a,{href:"./shovel#status",children:"Monitoring Shovels"})," in the overview Shovel plugin guide."]})]})}function x(e={}){let{wrapper:s}={...(0,r.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},57250(e,s,n){n.d(s,{A:()=>d});var i=n(74848);n(96540);var t=n(34164),r=n(57663);function l({children:e,className:s,hidden:n}){return(0,i.jsx)("div",{role:"tabpanel",className:(0,t.A)("tabItem_Ymn6",s),hidden:n,children:e})}function d({children:e,className:s,value:n}){let{selectedValue:t,lazy:o}=(0,r.uc)(),a=n===t;return!a&&o?null:(0,i.jsx)(l,{className:s,hidden:!a,children:e})}},50773(e,s,n){n.d(s,{A:()=>u});var i=n(74848);n(96540);var t=n(34164),r=n(88287),l=n(57663),d=n(28584),o=n(19863);function a({className:e}){let{selectedValue:s,selectValue:n,tabValues:r,block:o}=(0,l.uc)(),h=[],{blockElementScrollPositionUntilNextRender:c}=(0,d.a_)(),u=e=>{let i=e.currentTarget,t=r[h.indexOf(i)].value;t!==s&&(c(i),n(t))},x=e=>{let s=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{let n=h.indexOf(e.currentTarget)+1;s=h[n]??h[0];break}case"ArrowLeft":{let n=h.indexOf(e.currentTarget)-1;s=h[n]??h[h.length-1]}}s?.focus()};return(0,i.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,t.A)("tabs",{"tabs--block":o},e),children:r.map(({value:e,label:n,attributes:r})=>(0,i.jsx)("li",{role:"tab",tabIndex:s===e?0:-1,"aria-selected":s===e,ref:e=>{h.push(e)},onKeyDown:x,onClick:u,...r,className:(0,t.A)("tabs__item","tabItem_LNqP",r?.className,{"tabs__item--active":s===e}),children:n??e},e))})}function h({children:e}){return(0,i.jsx)("div",{className:"margin-top--md",children:e})}function c({className:e,children:s}){return(0,i.jsxs)("div",{className:(0,t.A)(r.G.tabs.container,"tabs-container","tabList__CuJ"),children:[(0,i.jsx)(a,{className:e}),(0,i.jsx)(h,{children:s})]})}function u(e){let s=(0,o.A)(),n=(0,l.OC)(e);return(0,i.jsx)(l.O_,{value:n,children:(0,i.jsx)(c,{className:e.className,children:(0,l.vT)(e.children)})},String(s))}},57663(e,s,n){n.d(s,{OC:()=>u,O_:()=>j,uc:()=>m,vT:()=>h});var i=n(74848),t=n(96540),r=n(56347),l=n(99989),d=n(96629),o=n(80618),a=n(41367);function h(e){return t.Children.toArray(e).filter(e=>"\n"!==e)}function c({value:e,tabValues:s}){return s.some(s=>s.value===e)}function u(e){let s,{defaultValue:n,queryString:i=!1,groupId:h}=e,u=function(e){let{values:s,children:n}=e;return(0,t.useMemo)(()=>{let e=s??t.Children.toArray(n).flatMap(e=>{if(!e)return[];if((0,t.isValidElement)(e)&&function(e){let{props:s}=e;return!!s&&"object"==typeof s&&"value"in s}(e))return[e];let s="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${s}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.
2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:s,attributes:n,default:i}})=>({value:e,label:s,attributes:n,default:i})),i=(0,o.XI)(e,(e,s)=>e.value===s.value);if(i.length>0)throw Error(`Docusaurus error: Duplicate values "${i.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[s,n])}(e),[x,m]=(0,t.useState)(()=>(function({defaultValue:e,tabValues:s}){if(0===s.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!c({value:e,tabValues:s}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${s.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let n=s.find(e=>e.default)??s[0];if(!n)throw Error("Unexpected error: 0 tabValues");return n.value})({defaultValue:n,tabValues:u})),[j,p]=function({queryString:e=!1,groupId:s}){let n=(0,r.W6)(),i=function({queryString:e=!1,groupId:s}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!s)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return s??null}({queryString:e,groupId:s});return[(0,d.aZ)(i),(0,t.useCallback)(e=>{if(!i)return;let s=new URLSearchParams(n.location.search);s.set(i,e),n.replace({...n.location,search:s.toString()})},[i,n])]}({queryString:i,groupId:h}),[v,f]=function({groupId:e}){let s=e?`docusaurus.tab.${e}`:null,[n,i]=(0,a.Dv)(s);return[n,(0,t.useCallback)(e=>{s&&i.set(e)},[s,i])]}({groupId:h}),g=c({value:s=j??v,tabValues:u})?s:null;return(0,l.A)(()=>{g&&m(g)},[g]),{selectedValue:x,selectValue:(0,t.useCallback)(e=>{if(!c({value:e,tabValues:u}))throw Error(`Can't select invalid tab value=${e}`);m(e),p(e),f(e)},[p,f,u]),tabValues:u,lazy:e.lazy??!1,block:e.block??!1}}let x=(0,t.createContext)(null);function m(){let e=t.useContext(x);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function j(e){return(0,i.jsx)(x.Provider,{value:e.value,children:e.children})}},28453(e,s,n){n.d(s,{R:()=>l,x:()=>d});var i=n(96540);let t={},r=i.createContext(t);function l(e){let s=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function d(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:l(e.components),i.createElement(r.Provider,{value:s},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.