1. Home
  2. Technical Documentation
  3. How to Add a RabbitMQ Trigger without a Queue Worker

How to Add a RabbitMQ Trigger without a Queue Worker

This article explains how to bridge an existing RabbitMQ broker to the Warewolf Execution Engine using the engine’s own in-process secure Service Bus trigger — without exposing RabbitMQ to Azure, without a second Function App in the request path, and without an HTTP hop between the message and the workflow. It’s the right fit when a customer already has RabbitMQ producing messages on-prem, wants those messages to execute a workflow on the engine as a specific, identifiable caller (not a shared system identity), and wants that caller’s own permissions enforced per message.

Download the Deployment Scripts. Download the Warewolf Azure Execution Engine deployment scripts from warewolf.io/release-notes.php and extract the .zip so that the scripts land in D:\ExecutionEngine\Scripts. All examples in this article assume that path. This article assumes the engine itself is already deployed — see Deploy to Azure Functions if it isn’t yet.

Why a trigger built into the engine, and not a separate worker process

RabbitMQ speaks AMQP 0.9.1; Azure Service Bus speaks AMQP 1.0 (or its own protocol). They can’t talk to each other directly. The shovel bridge uses two first-class, independently-provisioned pieces to connect them:

  • RabbitMQ’s own Shovel plugin — a dynamic, broker-managed forwarder that reads from an existing RabbitMQ queue and republishes each message, verbatim, onto a Service Bus queue over AMQP 1.0. No custom forwarding code, no extra process to keep alive.
  • A ServiceBusTrigger function bound directly inside the Lightweight engine’s own Function App (ServiceBusWorkflowTriggerFunction) — the same deployed app that serves /secure and /public HTTP routes also listens on the Service Bus queue. There is no separate compute step, no second Managed Identity making an outbound call on the caller’s behalf, and no second authorization implementation to keep in sync with the HTTP one — both call the identical IWorkflowPolicyMatcher.Evaluate(...).
 ┌──────────────┐  publish   ┌─────────────────┐   Shovel    ┌───────────────────────┐  trigger   ┌────────────────────────────┐
 │  RabbitMQ    │ ─────────▶ │  RabbitMQ        │ ──────────▶ │  Azure Service         │ ─────────▶ │  ServiceBusWorkflowTrigger  │
 │  producer    │            │  source queue     │  (AMQP     │  Bus queue             │  (message) │  Function — IN-PROCESS,     │
 └──────────────┘            └─────────────────┘   0.9.1→1.0) │  wwexecution-secure-   │            │  inside the Lightweight     │
                                                                │  trigger-queue         │            │  engine's own Function App  │
                                                                └───────────────────────┘            └──────────────┬──────────────┘
                                                                                                                       │ validates caller's own
                                                                                                                       │ bearer token, evaluates
                                                                                                                       │ IWorkflowPolicyMatcher
                                                                                                                       ▼
                                                                                                              Executes in-process
                                                                                                              (same engine, no HTTP hop)

The message carries the calling identity’s own delegated Entra token, not a shared system credential — so a given caller can only run the workflows their own secure.config permissions allow, exactly as if they’d called /secure/{workflow} over HTTP.

Message contract

Shovel forwards message bytes verbatim — it cannot reshape payloads. The RabbitMQ producer must publish exactly the JSON the trigger expects, and set the caller’s bearer token as an AMQP application property (Authorization), never inside the JSON body itself:

Body: { "workflow": "Hello World", "inputs": { "Name": "FromRabbitMq" }, "correlationId": "optional-caller-supplied-id" }
Application property "Authorization": "Bearer <caller's own Entra access token>"
  • workflow (required) — the workflow name, matched against secure.config exactly as an HTTP /secure/{workflow} path segment would be.
  • inputs (optional) — a string map, passed through identically to HTTP query-string inputs.
  • correlationId (optional) — caller-supplied idempotency/polling key. If omitted, the trigger falls back to the message’s native CorrelationId, then MessageId.
  • Authorization application property (required) — Bearer <token>, mirroring the HTTP Authorization header exactly. There is no route field — every message is evaluated as a secure, per-caller execution; there is no anonymous/public equivalent for this trigger.

If an existing RabbitMQ producer uses a different schema, it must be changed to emit this contract, or an adapter service must sit between the producer and the source queue — Shovel itself cannot transform payloads or inject the AMQP application property from a JSON field.

Getting the result — polling only, no push

The trigger doesn’t call anything back. A producer that needs the outcome publishes with a correlationId it generates itself, then polls GET /secure/servicebus-result/{correlationId} (itself protected by the engine’s ordinary HTTP authorization pipeline, requiring WorkflowPermission.View) until a terminal status — Succeeded, Failed, Denied, InvalidToken — comes back, or a 404 if the message hasn’t been processed yet. Push-style delivery (reply queue, webhook, SignalR) is explicitly out of scope for this trigger.

Note the audience split: the token embedded in the message‘s Authorization property is validated against WAREWOLF_ENTRA_CONFIG‘s serviceBusAudience field (Prerequisites, above), but the token used to poll the result goes through the engine’s ordinary /secure HTTP pipeline and is validated against that same setting’s separate audience/clientId fields instead. A caller usually needs a token minted for each audience — one to trigger, one to poll — unless both app registrations happen to share an audience.

Prerequisites

Requirement Notes
PowerShell 7.0+, Azure CLI 2.55.0+ Same as every other script in the deployment scripts zip.
RabbitMQ Shovel plugins enabled on the broker One-time, broker-host admin action: rabbitmq-plugins enable rabbitmq_shovel rabbitmq_shovel_management. Configure-RabbitMqShovel.ps1 probes for this and tells you if it’s missing — it cannot enable it remotely.
A broker-side TLS hostname-check fix Required before any shovel can connect to a real Service Bus namespace — see the callout below. Also broker-host admin, also not automatable remotely.
The engine’s Function App already has a system-assigned Managed Identity Enable-ServiceBusSecureTrigger.ps1 deliberately does not create one on a live/shared app — enable it first if it isn’t already there: az functionapp identity assign --name <app> --resource-group <rg>.
A dedicated Entra App Registration for the Service Bus audience This is not the same registration as the engine’s ordinary HTTP audience, and it is not a daemon/client-apps registration like Client Apps — the trigger validates every caller’s own token against this audience directly (confused-deputy prevention). Creating it and issuing tokens from it is the operator’s own concern; this bridge only wires the engine to validate against it.

Required broker fix — TLS hostname check. Azure Service Bus presents a wildcard certificate (*.servicebus.windows.net). Erlang’s default certificate-hostname check does a literal match, not a wildcard-aware one, so without this fix every shovel connection to a real Service Bus namespace fails with {tls_alert,{bad_certificate,{bad_cert,{hostname_check_failed, ...}}}} in the broker’s own log (not visible via the Management API). Add this to the broker’s advanced.config (%APPDATA%\RabbitMQ\advanced.config on Windows, /etc/rabbitmq/advanced.config on Linux) and restart the broker:

[
  {amqp10_client, [
    {ssl_options, [
      {customize_hostname_check, [
        {match_fun, public_key:pkix_verify_hostname_match_fun(https)}
      ]}
    ]}
  ]}
].

This keeps full TLS peer/chain validation enabled — it only fixes the hostname match, it doesn’t weaken certificate checking. On Erlang/OTP 26+ brokers you’ll also need to pass a CA bundle on the shovel’s destination URI (-DestUriCaCertFile on Configure-RabbitMqShovel.ps1, step 3 below) or the shovel crash-loops with {cacerts, undefined} — OTP 26 stopped falling back to an implicit trust store.

Step 0 — Deploy the Lightweight Execution Engine (first-time deploy)

Everything above assumes the engine is already running somewhere. If it isn’t yet, deploy it with Deploy-WwExecutionEngine.ps1 from the same D:\ExecutionEngine\Scripts folder as every other script in this article.

Deploy-WwExecutionEngine.ps1 deploys an already-published package — it does not build one for you. Download the published Execution Engine package alongside the deployment scripts from warewolf.io/release-notes.php and extract it locally (this article assumes D:\ExecutionEngine\Publish) before running the command below. See Deploy to Azure Functions for the full first-deploy walkthrough if any of this step is unfamiliar.

cd D:\ExecutionEngine\Scripts

.\Deploy-WwExecutionEngine.ps1 `
    -ResourceGroup           $ResourceGroup `
    -Location                $Location `
    -StorageAccount          $StorageAccount `
    -AppName                 $EngineAppName `
    -PublishPath             'D:\ExecutionEngine\Publish' `
    -WorkflowsSourcePath     'D:\ExecutionEngine\Resources' `
    -LicenseCheckEnabled:$true `
    -LicenseConfigPath       'D:\ExecutionEngine\Warewolf License.secureconfig' `
    -EnablePersistence:$true `
    -PersistenceSettingsPath 'D:\ExecutionEngine\Persistence\persistencesettings.json' `
    -PersistenceDbSourcePath 'D:\ExecutionEngine\Persistence\persistencesettingsdbsource.bite' `
    -ServiceBusMaxConcurrentCalls 2 `
    -ServiceBusTriggerMaxConcurrentExecutions 2 `
    -KeyVaultName             $KeyVaultName `
    -KeyVaultSecretName       $KeyVaultSecretName `
    -EnablePerformanceCounters:$true

Two of these switches matter directly to this bridge, and are easy to conflate with each other:

  • -ServiceBusMaxConcurrentCalls sets host.json’s extensions.serviceBus.maxConcurrentCalls — how many Service Bus messages the Functions host dispatches to the trigger concurrently. This is the upstream cap.
  • -ServiceBusTriggerMaxConcurrentExecutions sets the trigger’s own in-process semaphore (ServiceBusTriggerOptions.MaxConcurrentExecutions, default 8) — how many workflow executions this instance runs at once, downstream of the host’s dispatch. It’s one of five deploy-time tunables (alongside -ServiceBusTriggerJtiWindowHours, -ServiceBusTriggerExecutionTimeoutSeconds, -ServiceBusTriggerSlotWaitTimeoutSeconds, -ServiceBusTriggerSettlementTimeoutSeconds) written into Settings/executionengine.settings.json‘s serviceBusTrigger section — these have no app-setting/env-var fallback, so if you skip them here you can only change them later by re-running this script or hand-editing that staged file.

-EnablePersistence:$true is not optional for a production bridge. This trigger’s replay-prevention (jti) and idempotency (correlationId) store falls back to an in-memory ConcurrentDictionary whenever Config.Persistence is off — correct for a single instance only. The moment the Function App scales out under a real message burst (exactly the scenario this bridge exists for), each instance would track replay/idempotency state independently, silently reopening both the replayed-token and duplicate-delivery gaps “Backing store” in docs/ServiceBusSecureTrigger-Architecture.md describes. Supply -PersistenceSettingsPath/-PersistenceDbSourcePath pointing at your own Hangfire/SQL persistence config and DB source so the store is durable and consistent across instances.

This deploy does not touch anything Service-Bus-namespace-specific — no queue, no RBAC role, no WAREWOLF_ENTRA_CONFIG.serviceBusAudience. That remains the separate, deliberate Enable-ServiceBusSecureTrigger.ps1 step below, run once the engine above is actually up.

Unlike every other script in this article, Deploy-WwExecutionEngine.ps1 is interactive by default — omit -NonInteractive (as above) and it prompts for anything you didn’t pass. Add -NonInteractive once you’re scripting this into your own automation, at which point every required value must be supplied explicitly or it throws early. -SkipAuthProvisioning above skips Entra/Easy Auth setup for the engine’s HTTP routes (Configure-WwExecutionAuth.ps1) — it does not block triggering a workflow via this bridge: Enable-ServiceBusSecureTrigger.ps1 writes its own tenantId/serviceBusAudience into WAREWOLF_ENTRA_CONFIG independently, merging with (or creating) that setting either way. It does block getting the result back, thoughGET /secure/servicebus-result/{correlationId} (Step 4) runs through the engine’s ordinary /secure HTTP pipeline, which needs the audience/clientId fields that only Configure-WwExecutionAuth.ps1 writes into WAREWOLF_ENTRA_CONFIG. Skip it and every poll comes back 401 Authentication required, even for a token that triggered the workflow successfully. Omit -SkipAuthProvisioning and supply -AuthConfigPath instead, or run Configure-WwExecutionAuth.ps1 as its own follow-up step, before relying on this bridge’s result path.

Step 1 — Create the Service Bus namespace and enable the trigger

1a — Create the namespace (if it doesn’t already exist)

Enable-ServiceBusSecureTrigger.ps1 (next step) provisions the trigger queue, but it does not create the namespace — it fails fast if -ServiceBusNamespace doesn’t already exist. Create it first:

az servicebus namespace create `
  --name $ServiceBusNamespace --resource-group $ResourceGroup --location $Location `
  --sku Standard

Use Standard, not Basic. The trigger’s listen connection authenticates via Azure AD (Managed Identity, RBAC role Azure Service Bus Data Receiver) — Basic tier does not support Azure AD data-plane authentication at all, and cannot reliably host the per-queue SAS authorization rule the shovel’s send side needs either (Step 2a). This matches the SKU default the worker-based bridge’s own deploy script uses for the same reason.

1b — Create the trigger queue and wire up the engine

The queue itself is created for you, idempotently, by Enable-ServiceBusSecureTrigger.ps1 — you don’t need a separate az servicebus queue create call. For reference, this is the equivalent command the script runs under the hood (dead-lettering on, configurable delivery budget):

az servicebus queue create `
  --name wwexecution-secure-trigger-queue --namespace-name $ServiceBusNamespace --resource-group $ResourceGroup `
  --enable-dead-lettering-on-message-expiration true `
  --max-delivery-count 10 --lock-duration PT5M

Rather than running that by hand, run the script — it also grants the engine’s Managed Identity Azure Service Bus Data Receiver on the namespace and sets the app settings the trigger binds to, all in one idempotent pass:

.\Enable-ServiceBusSecureTrigger.ps1 `
  -FunctionAppName $EngineAppName -ResourceGroup $ResourceGroup `
  -ServiceBusNamespace $ServiceBusNamespace `
  -TriggerQueueName wwexecution-secure-trigger-queue `
  -EntraTenantId $TenantId -EntraServiceBusAudience $ServiceBusAudience `
  -DryRun

Drop -DryRun once the preview looks right. This provisions, in order: the trigger queue on the namespace (dead-lettering, configurable -MaxDeliveryCount/-LockDuration), a role assignment granting the engine’s own Managed Identity Azure Service Bus Data Receiver on the namespace (no worker identity, no separate app — the engine listens directly), and the app settings the trigger binds to (ServiceBusConnection__fullyQualifiedNamespace, WAREWOLF_SERVICEBUS_TRIGGER_QUEUE, and the tenantId/serviceBusAudience fields of WAREWOLF_ENTRA_CONFIG, merged rather than overwritten so it doesn’t clobber whatever Configure-WwExecutionAuth.ps1 already set for the HTTP path).

The script’s own default for -TriggerQueueName is wwexecution-secure-trigger-queue-e2e — a test-scoped name, deliberately not the production default used above. Always pass -TriggerQueueName wwexecution-secure-trigger-queue (or your own choice) explicitly for a real deployment.

This script is not run by any CI job — it mutates a live Function App’s auth surface, so treat it as a deliberate, reviewed operator step. It also does not assign the Function App’s Managed Identity in the first place (that’s the “already has a system-assigned Managed Identity” prerequisite above), create the Entra App Registration behind -EntraServiceBusAudience, mint any tokens, or grant secure.config permission to run a workflow — those are the remaining manual steps below.

Step 2 — Authorize the trigger’s inputs: the shovel’s send credential and the caller’s permission

Two independent grants are needed here, and neither is created by a script:

2a — Create the shovel’s destination SAS rule

Unlike the worker-based bridge, nothing provisions a Send-only SAS rule on the trigger queue for you — create it once:

az servicebus queue authorization-rule create `
  --resource-group $ResourceGroup --namespace-name $ServiceBusNamespace `
  --queue-name wwexecution-secure-trigger-queue `
  --name shovel-send --rights Send

This is the least-privilege credential the RabbitMQ Shovel plugin will use as its destination — it can never Listen or Manage. (See “Security model” below for why this has to be a SAS key rather than the engine’s Managed Identity.)

2b — Grant the calling identity permission to run the target workflow

The token carried in each message is evaluated by IWorkflowPolicyMatcher exactly like an HTTP caller’s — which denies by default. Add a secure.config WindowsGroupPermissions row granting the caller’s own group/role Execute=true on every workflow the bridge will call — see Security — secure.config. A validly-signed token for the right audience with no matching permission row still comes back Denied, not Succeeded.

Step 3 — Configure the RabbitMQ shovel

This configures a dynamic shovel via the RabbitMQ Management HTTP API — nothing is written to the broker’s static config, and it’s safe to re-run. The destination SAS key is fetched live via az and never written to disk.

.\Configure-RabbitMqShovel.ps1 `
  -RabbitMqManagementUri "https://<broker-host>:15671" `
  -RabbitMqUsername <user> -RabbitMqPassword <SecureString> `
  -ShovelName wwexecution-shovel `
  -SourceHost <broker-host> -SourceQueue <existing-rabbitmq-queue> `
  -ServiceBusNamespace $ServiceBusNamespace -ServiceBusQueueName wwexecution-secure-trigger-queue `
  -ServiceBusResourceGroup $ResourceGroup -ServiceBusSasKeyName shovel-send `
  -DestUriCaCertFile /etc/ssl/certs/ca-certificates.crt

Four parameters here are easy to under-specify since some look interchangeable at a glance:

  • -ShovelName — names the dynamic shovel parameter itself (default wwexecution-shovel, used above for clarity). This is not just a label: whatever you pick here is what Monitor-RabbitMqShovel.ps1 (Step 5) polls for by name, so keep the two in sync — if you configure more than one shovel against the same broker (e.g. separate production/loadtest bridges), give each a distinct name and monitor each one individually.
  • -SourceHost / -SourcePort — the shovel’s own AMQP 0.9.1 consume connection to the source broker (default port 5672), separate from -RabbitMqManagementUri, which is only the HTTP management API the script itself talks to (default port 15671/15672) to create the dynamic parameter. In the overwhelmingly common case these point at the same broker, just different ports/protocols — -SourceHost is REQUIRED regardless, the script does not infer it from -RabbitMqManagementUri.
  • -SourceQueue — the existing RabbitMQ queue your producer already publishes to. Unchanged by this script; the producer keeps publishing exactly as it does today. This is the RabbitMQ-side counterpart to the Service Bus -ServiceBusQueueName on the other side of the bridge — don’t confuse the two when reading the command back.
  • -DestUriCaCertFile — a CA bundle path on the broker host (not on the machine running this script — the path is never validated locally), appended to the shovel’s destination URI as &cacertfile=<path>. The value above, /etc/ssl/certs/ca-certificates.crt, is the standard system bundle on the Debian-based official RabbitMQ Docker image; use your own platform’s path (e.g. /etc/pki/tls/certs/ca-bundle.crt on RHEL-family, or a bundle you ship yourself on Windows). Required on Erlang/OTP 26+ brokers — see the TLS callout above; harmless on older brokers, which is why it’s shown inline rather than as an afterthought. Omit it only if you’ve confirmed your broker predates OTP 26.

-SourceUsername/-SourcePassword default to -RabbitMqUsername/-RabbitMqPassword when omitted (same broker, same admin credentials, as above) — override them if you’d rather the Shovel consume the source queue under a separate, least-privilege account instead of your management-API admin login.

-DestUriVerifyNone exists as a last-resort escape hatch that disables all peer certificate validation; it’s a diagnostic tool, not a recommended setting, and it is mutually exclusive with -DestUriCaCertFile — passing both throws, since verify_none makes an explicit CA bundle moot.

Step 4 — Verify

# Confirm the queue exists and check its depth:
az servicebus queue show --namespace-name $ServiceBusNamespace --resource-group $ResourceGroup --name wwexecution-secure-trigger-queue -o table

# Or schedule the standalone health monitor (Task Scheduler/cron/Azure Automation —
# RabbitMQ is customer/on-prem infra, not something a Function can reliably poll):
.\Monitor-RabbitMqShovel.ps1 -RabbitMqManagementUri "https://<broker-host>:15671" `
  -RabbitMqUsername <user> -RabbitMqPassword <SecureString> -ShovelName wwexecution-shovel

Publish a message carrying a valid Authorization application property to the RabbitMQ source queue, then poll the result:

GET /secure/servicebus-result/{correlationId}
Authorization: Bearer <a token allowed to View that workflow>

A terminal InvalidToken result means the token failed validation (wrong audience/issuer, expired, or malformed — see the dead-letter sub-reasons below); a terminal Denied result means the token validated fine but the caller has no secure.config Execute row for that workflow (re-check Step 2b). A 404 just means the message hasn’t reached the trigger yet — keep polling before assuming failure.

The Management API reports a healthy, actively-forwarding shovel as either running or flowflow just means RabbitMQ’s own flow control is briefly throttling it (e.g. transient backpressure from the destination). It is not a failure state; don’t alert on it.

Security model

  • The Shovel’s destination credential is still a queue-scoped, Send-only SAS rule (Step 2a) — RabbitMQ’s built-in Shovel plugin only speaks SASL PLAIN with a policy-name/key pair, so it can never use the engine’s Managed Identity, regardless of which model receives on the other end.
  • The listen side is different from the worker-based bridge: the Lightweight engine’s own system-assigned Managed Identity is granted Azure Service Bus Data Receiver directly on the namespace — there is no separate Function App, and no second identity in the picture at all.
  • Two independent trust boundaries are enforced, not one:
    1. Transport — who can put a message on the queue / receive from it. Enforced entirely by Azure (namespace RBAC via Managed Identity for the listen side; the Send-only SAS rule for the shovel).
    2. Message/caller — once a message is received, is this specific caller allowed to run this specific workflow? Passing the transport boundary only proves an authorized producer put a message on the queue — it does not prove the message’s content is authorized. The trigger closes that gap by requiring and validating a per-message bearer token before ever calling IWorkflowExecutor.
  • A stolen or replayed token cannot be reused across messages: the token’s jti claim is checked atomically (Hangfire-backed when the engine’s persistence store is enabled, in-memory otherwise) across every instance.
  • Redelivery (Service Bus’s at-least-once guarantee) does not re-execute a workflow: the same idempotency store also tracks correlationId, and a redelivered message returns the previously recorded result instead.
  • The destination Service Bus namespace must keep local (SAS) authentication enabled (disableLocalAuth = false) — this is unchanged from the worker-based bridge, since it governs the Shovel’s send-side connection, not the trigger’s listen side. If a security baseline flips this to true, the shovel stops connecting even though the engine’s own Managed Identity listen connection is untouched.
  • Rotate the shovel-send SAS key per your normal key-rotation schedule; rotating it requires re-running Configure-RabbitMqShovel.ps1 so the Shovel picks up the new key.

Troubleshooting

Symptom Likely cause Fix
Shovel terminated, reason "failed to connect to destination" Either the TLS hostname-check fix isn’t applied, or disableLocalAuth has drifted to true on the namespace — both produce this identical message. Check the broker’s own log for a hostname_check_failed TLS alert (apply the advanced.config fix above) vs. run az servicebus namespace show --query disableLocalAuth and restore false if it drifted.
Shovel stuck at "starting", never reaches running/flow OTP 26+ broker missing a CA bundle on the destination URI — crash-loops with {cacerts, undefined} in the broker log, too fast for the Management API to catch between retries. Re-run Configure-RabbitMqShovel.ps1 with -DestUriCaCertFile pointing at your platform’s CA bundle.
Every message dead-letters with reason InvalidToken:MissingAuthorizationProperty The RabbitMQ producer published the token inside the JSON body (matching the old worker-based contract) instead of the message’s Authorization application property. Fix the producer to set the AMQP application property, per “Message contract” above.
Every message dead-letters with reason InvalidToken:AudienceInvalid or :SignatureInvalid/:IssuerInvalid/:Expired The token was minted for the wrong audience (e.g. the engine’s ordinary HTTP audience instead of the dedicated Service Bus audience), or is malformed/expired. Confirm the producer requests a token for exactly the -EntraServiceBusAudience configured in Step 1, and that WAREWOLF_ENTRA_CONFIG‘s tenantId matches the issuing tenant.
Terminal result is Denied at GET /secure/servicebus-result/{correlationId} The token validated fine, but the caller’s identity has no matching secure.config Execute row for the workflow. Re-check Step 2b’s secure.config row against the caller’s actual claims/group.
GET /secure/servicebus-result/{correlationId} keeps returning 404 Either the message hasn’t reached the trigger yet, or the trigger isn’t provisioned/enabled on this app at all. Confirm delivery via the Service Bus queue’s message count; then confirm the four app settings from Step 1 are actually present with az functionapp config appsettings list.
rabbitmq-plugins enable instructions on every Configure-RabbitMqShovel.ps1 run rabbitmq_shovel/rabbitmq_shovel_management aren’t enabled on the broker. Run the exact rabbitmq-plugins enable command the script prints, once, on the broker host.

Teardown

Neither Enable-ServiceBusSecureTrigger.ps1 nor this bridge has a dedicated rollback companion. To disable the trigger without touching anything else the Function App does, set the standard Azure Functions kill-switch app setting: AzureWebJobs.ServiceBusWorkflowTrigger.Disabled=true. To remove it entirely, undo each of Step 1/2a manually: the app settings (ServiceBusConnection__fullyQualifiedNamespace, WAREWOLF_SERVICEBUS_TRIGGER_QUEUE, and the merged fields of WAREWOLF_ENTRA_CONFIG), the Azure Service Bus Data Receiver role assignment, the shovel-send SAS rule, and the trigger queue itself. The shovel can be removed via the RabbitMQ Management UI or API (DELETE /api/parameters/shovel/{vhost}/{name}) — deleting it does not touch the Service Bus queue.

See also

  • Scripts/Enable-ServiceBusSecureTrigger.ps1 — wires up the queue, RBAC, and app settings on an already-deployed engine.
  • Scripts/Configure-RabbitMqShovel.ps1 — configures the RabbitMQ side.
  • Scripts/Monitor-RabbitMqShovel.ps1 — standalone health monitor for scheduled polling.
  • docs/ServiceBusSecureTrigger-Architecture.md — full internal architecture reference for the trigger itself: topology, failure classification, dead-letter sub-reasons, and how it relates to the separate worker-based bridge.
  • docs/ShovelBridge-Architecture.md — the shovel/RabbitMQ side’s own architecture reference, including every root-caused TLS/shovel failure mode this article’s troubleshooting table summarizes.
  • Security — secure.config — the permission model each caller’s token is evaluated against.
  • Deploy to Azure Functions — deploying the engine itself, if it isn’t already up.
FacebookTwitterLinkedInGoogle+Email
Updated on September 4, 2026

Was this article helpful?

Related Articles

Enjoying Warewolf?

Write a review on G2 Crowd
Stars