Skip to content

fix(queue): handle RabbitMQ function queue DLQs - #613

Open
guibeira wants to merge 2 commits into
mainfrom
fix/rabbitmq-function-queue-dlq
Open

fix(queue): handle RabbitMQ function queue DLQs#613
guibeira wants to merge 2 commits into
mainfrom
fix/rabbitmq-function-queue-dlq

Conversation

@guibeira

@guibeira guibeira commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • resolve bare named function queues to their RabbitMQ function-queue DLQ topology
  • isolate DLQ inspection and redrive operations on disposable AMQP channels
  • preserve normalized RabbitMQ DLQ messages in the public browse response
  • cover bare-name browse/redrive and channel-isolation regressions

Root cause

list_topics exposes named function queues using their bare name, but RabbitMQ DLQ operations interpreted that value as a regular topic. The resulting passive declaration targeted a queue that did not exist, causing RabbitMQ to close the shared AMQP channel. RabbitMQ also returned normalized DLQ objects while the public function only attempted to deserialize legacy Job values, silently dropping those messages.

Impact

Named RabbitMQ function queues now appear in DLQ listings, their messages can be browsed and redriven using the public queue name, and a failed DLQ inspection cannot stop unrelated consumers.

Fixes iii-hq/iii#2017

Smoke test

The recording runs the full III flow against RabbitMQ through Docker Compose. It first reproduces all three failures with queue/v0.2.2, then verifies the same flow with this branch.

Issue #2017 III RabbitMQ smoke test

Validation

  • cargo fmt --all -- --check
  • git diff --check
  • cargo test (124 unit tests, 2 durability E2E tests, 5 RabbitMQ E2E tests, and 2 Redis E2E tests)
  • cargo clippy --all-targets --all-features -- -D warnings
  • full III smoke comparison between queue/v0.2.2 and this branch with RabbitMQ in Docker Compose

Summary by CodeRabbit

  • Bug Fixes

    • Improved dead-letter queue inspection, counting, and redrive behavior for function queues.
    • Prevented failed inspections of missing queues from disrupting active message consumers.
    • Preserved normalized dead-letter message details, including errors, retry counts, timestamps, and sizes.
    • Improved queue statistics accuracy for primary and dead-letter queues.
  • Reliability

    • Redriving messages from function-queue dead-letter queues now resolves destinations correctly and avoids failures when queue metadata is unavailable.

@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 28, 2026 1:19pm
workers-tech-spec Ready Ready Preview, Comment Jul 28, 2026 1:19pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

RabbitMQ DLQ operations now resolve configured function queues to internal topology names and use isolated channels for inspection, counting, redrive, and statistics. DLQ decoding accepts normalized records, and tests cover redrive behavior and missing-queue channel safety.

Changes

RabbitMQ DLQ behavior

Layer / File(s) Summary
DLQ routing and channel isolation
queue/src/adapters/rabbitmq/adapter.rs
DLQ operations resolve function-queue names, use dedicated channels, update queue statistics, and avoid panicking during function-queue redrive.
Normalized DLQ decoding
queue/src/functions.rs
dlq_messages accepts normalized DlqMessage records as well as raw Job values and preserves normalized fields.
End-to-end DLQ validation
queue/tests/e2e_rabbitmq.rs
Integration tests verify function-queue DLQ inspection, redrive cleanup, and consumer-channel preservation after missing-queue errors.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QueueAPI
  participant RabbitMQAdapter
  participant RabbitMQ
  participant Consumer
  QueueAPI->>RabbitMQAdapter: inspect function-queue DLQ
  RabbitMQAdapter->>RabbitMQ: resolve internal DLQ name
  RabbitMQAdapter->>RabbitMQ: open operation channel
  RabbitMQ-->>RabbitMQAdapter: return DLQ data
  RabbitMQAdapter-->>QueueAPI: return messages or count
  Consumer->>RabbitMQ: continue using consumer channel
Loading

Possibly related issues

  • iii-hq/iii#2017 — Covers the same function-queue DLQ name resolution, normalized message decoding, and shared-channel failures.
  • iii-hq/iii#1653 — Addresses consistent topic and function-queue resolution across DLQ operations.

Possibly related PRs

  • iii-hq/workers#424 — Modifies the same RabbitMQ adapter DLQ inspection and redrive paths.

Suggested reviewers: ytallo

Poem

A rabbit found a queue astray,
And mapped its hidden path today.
A fresh channel kept watchful guard,
While DLQ notes were safely parsed.
Redrive hopped, the count fell through—
Consumers stayed calm, as rabbits do.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main RabbitMQ function-queue DLQ fix.
Linked Issues check ✅ Passed The changes resolve bare-name DLQ lookup, isolate AMQP channels, and preserve normalized DLQ messages as required by #2017.
Out of Scope Changes check ✅ Passed The added tests and helpers are directly related to the RabbitMQ DLQ fix, with no clear unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rabbitmq-function-queue-dlq

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 49 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

@guibeira guibeira added the no-ticket PR deliberately has no Linear ticket (bump/typo/CI-only) label Jul 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
queue/src/adapters/rabbitmq/adapter.rs (1)

525-573: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Enable and validate publisher confirms before acknowledging DLQ redrive messages.

operation_channel("DLQ redrive") creates a channel without confirm_select, so the function-queue basic_publish future resolves to NotRequested; if the publish fails, the DLQ delivery can still be removed and lost. Enable confirms on this channel and reject non-is_ack() confirmations before acknowledging.

Proposed fix
 let channel = self.operation_channel("DLQ redrive").await?;
+channel
+    .confirm_select(ConfirmSelectOptions::default())
+    .await
+    .map_err(|e| anyhow::anyhow!("Failed to enable redrive publisher confirms: {}", e))?;

- channel
+let confirmation = channel
     .basic_publish(
         &names.exchange(),
         queue_name,
         BasicPublishOptions::default(),
         &delivery.delivery.data,
         properties,
     )
     .await
     .map_err(|e| anyhow::anyhow!("Failed to republish: {}", e))?
     .await
     .map_err(|e| anyhow::anyhow!("Failed to confirm: {}", e))?;
+if !confirmation.is_ack() {
+    anyhow::bail!("RabbitMQ did not acknowledge DLQ redrive publish");
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@queue/src/adapters/rabbitmq/adapter.rs` around lines 525 - 573, Update the
DLQ redrive flow around operation_channel("DLQ redrive") to enable publisher
confirms on the channel before publishing. In the function-queue republish path,
validate the confirmation returned by basic_publish and reject any non-is_ack()
result before acknowledging the original DLQ delivery, preserving the existing
error propagation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@queue/src/adapters/rabbitmq/adapter.rs`:
- Around line 525-573: Update the DLQ redrive flow around operation_channel("DLQ
redrive") to enable publisher confirms on the channel before publishing. In the
function-queue republish path, validate the confirmation returned by
basic_publish and reject any non-is_ack() result before acknowledging the
original DLQ delivery, preserving the existing error propagation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d91acbf0-cfa8-4270-9366-1eb8ea2b9fa5

📥 Commits

Reviewing files that changed from the base of the PR and between a88137b and ae70209.

📒 Files selected for processing (3)
  • queue/src/adapters/rabbitmq/adapter.rs
  • queue/src/functions.rs
  • queue/tests/e2e_rabbitmq.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-ticket PR deliberately has no Linear ticket (bump/typo/CI-only)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RabbitMQ function-queue DLQ browsing uses the wrong queue name

1 participant