Skip to content

Service Bus: GroupId as SessionId, session receive, safe delayed retry, fast emulator drain - #103

Merged
niemyjski merged 18 commits into
mainfrom
feature/queue-group-id
Oct 14, 2026
Merged

niemyjski merged 18 commits into
mainfrom
feature/queue-group-id

Conversation

@niemyjski

@niemyjski niemyjski commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

What this adds

Support for the new QueueEntryOptions.GroupId from Foundatio core (FoundatioFx/Foundatio#579).

  • GroupId is sent as the Service Bus SessionId. An explicit AzureServiceBusQueueEntryOptions.SessionId still wins when both are set.
  • IQueueEntry.GroupId is filled from SessionId, both on the Enqueued event entry and on dequeue.
  • SessionId is copied onto the scheduled message used for a delayed retry, so GroupId survives abandon.
  • Session-enabled queues (RequiresSession = true) can now be received from. Each dequeue accepts the next available session and receives one message. The entry holds that session until it is completed, abandoned or dead-lettered, so each group is processed one message at a time, in order. RenewLockAsync renews the session lock. On these queues SupportsGroupId is true; every message needs a GroupId.

Bug fixes

  • A failed delayed-retry send no longer loses the original message. The scheduled copy is now sent first and the original completed after. If the complete fails, the original can be redelivered alongside the retry, which is Service Bus's documented at-least-once contract (message loss and duplicates); handlers should be idempotent.
  • Emulator DeleteQueueAsync no longer sleeps or leaks messages into later tests. The emulator path (used only when the connection string has UseDevelopmentEmulator=true) drains instead of deleting. It used to poll for 5 seconds on every call even when the queue was empty, and it couldn't see messages locked by an unsettled entry. Those reappeared once the 1-minute lock expired, inside whichever test ran next. Now:
    • The drain peeks the queue and stops as soon as it is empty. Active messages are received and completed. For scheduled messages it waits only until the earliest one is due, capped at 30s; the emulator ignores CancelScheduledMessagesAsync, so they can't be cancelled.
    • DeleteQueueAsync first completes any message this queue instance dequeued but never settled.

Test suite speed

Emulator test run
main CI 9m 04s
This branch before the drain fix (local) ~19 min, cross-test failures, appeared hung
This branch now, PR CI 38s, 98 passed, 0 failed, 12 skipped
This branch now, push CI 37s, 98 passed, 0 failed, 12 skipped

Every queue test paid the 5-second drain three times (setup, cleanup, and the harness's per-test DisposeAsync), which accounted for roughly 16s of each test. A simple enqueue/dequeue test went from 16.5s to 0.43s. Locally the full suite passed twice in a row in 39s with no leaked-lock warnings.

Tests

  • AzureServiceBusSessionQueueTests runs the shared QueueTestBase suite against a session-enabled emulator queue (foundatio-test-queue-sessions, added to Config.json). It also covers per-group ordering (A1, A2 before B1, one in flight per group) and renew/abandon/complete on the session receiver. Four shared tests that enqueue without a GroupId are skipped, because session queues reject them.
  • GroupId sent as SessionId, explicit SessionId wins, and GroupId kept on delayed retry.
  • Shared GroupId resolver tests from QueueTestBase.

Built against 13.0.5-preview.0.10 of core/TestHarness.

Not in this PR (draft follow-ups, held for the next release)

  • Building the retry from the received message so PartitionKey, Subject, ContentType and other fields are kept, and using a new MessageId when RequiresDuplicateDetection is on (scheduled messages count for duplicate detection, so today's retry is dropped on those queues).
  • A shared, backed-off worker loop that keeps running after dequeue or abandon errors.

Docs

azure.md documents RequiresSession ordering; provider-behavioral-gaps.md marks Service Bus GroupId as ordered per group on session-enabled queues and describes the at-least-once retry.

Compatibility

Only adds behavior. Receiving from a RequiresSession queue used to fail with an SDK error and now works. Emulator-only: DeleteQueueAsync now also completes messages this instance has in flight. Stable release ordering is coordinated with core (FoundatioFx/Foundatio#579).

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-14T15:33:11.452125Z 8653e24 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6add28c23

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
@niemyjski

niemyjski commented Oct 5, 2026 •

Copy link
Copy Markdown
Member Author

Updated 2026-10-06: reviewed repairs are now pushed at 48e75205b39bcb80aa30ddcbab1a203bb1ad30b8. The push build and PR build still fail compilation before tests because the released Foundatio 13.0.4 package lacks the new GroupId APIs. A core/TestHarness release containing #579, followed by provider dependency updates, remains required. Sibling-source tests do not clear this standalone gate.

The build caller is pinned to guarded core commit a28d0f736d9124431de09764c56aff77fbdc1d5d; both runs resolve that exact workflow and skip the test/package/publishing steps after the compile failure. Feature-branch package publication is also excluded by the approved guard. Dependency versions are unchanged; no packages were published by these runs.

Repair and local validation evidence

Follow-up repair registers the shared empty-GroupId test and isolates RequiresSession guards from service-dependent fixture cleanup. The two standalone dequeue/worker guard tests pass against sibling core source; both library target frameworks build with zero warnings/errors. The shared empty-group wrapper is registered but was not run against a Service Bus emulator in this follow-up.

Session-enabled receiving remains a pre-existing unsupported capability; this work is producer-only and adds no session receiver. No live Service Bus validation is claimed.

These local checks ran on 2026-10-05. Application/test source is unchanged from those validated repair commits; this follow-through added only the approved workflow guard/pin. YAML parsing and diff checks passed. No new local application test run is claimed.

Service Bus ignores SessionId unless the queue requires sessions, and this provider cannot receive from session-enabled queues, so GroupId cannot change delivery. Remove SupportsGroupId so the base queue logs that, and add a regression test.

Also consume the queue-group-id nightly of Foundatio and Foundatio.TestHarness until a release is available.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

1 similar comment
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@niemyjski

niemyjski commented Oct 6, 2026 •

Copy link
Copy Markdown
Member Author

Downstream CI pin: this PR consumes Foundatio and Foundatio.TestHarness 13.0.5-preview.0.10 from the Feedz feed, published from main after FoundatioFx/Foundatio#579 merged. No branch nightly is needed anymore.

A failed send after completing the original lost the message. The retry is now sent first, and gets a new MessageId when duplicate detection is on so it is not dropped as a duplicate. The worker loop now logs SDK timeouts and waits at least one second after a dequeue error. Adds the delayed-retry GroupId test.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@niemyjski niemyjski changed the title Service Bus: map GroupId to SessionId and preserve message fields on retry Service Bus: map GroupId to SessionId and make delayed retry send before complete Oct 8, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

…tate-driven and settle in-flight entries on delete

Drain peeks the queue instead of sleeping for 5s per call, waits only for a peeked scheduled message's due time (the emulator ignores CancelScheduledMessagesAsync), and DeleteQueueAsync completes messages this instance dequeued but never settled so their locks cannot leak into later tests. Emulator suite: ~19 min with cross-test failures -> 39s green.
@niemyjski niemyjski changed the title Service Bus: map GroupId to SessionId and make delayed retry send before complete Service Bus: GroupId as SessionId, session receive, safe delayed retry, fast emulator drain Oct 14, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ef8fae35a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ded01a755

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs
…rs, drain scan type, worker error backoff, TimeProvider for schedules

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ab8077a55

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
… send, release expired unsettled entries, share accept/receive deadline, avoid retry copies with duplicate detection, count copy redeliveries

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 45430298db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs Outdated
…cked entries, grace period before releasing expired locks, document RetryDelay

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eca2270a89

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs
Comment thread src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs
@niemyjski

Copy link
Copy Markdown
Member Author

Production hardening pass (4543029, eca2270):

  • Session queues: abandon keeps the message at the head of its group (RetryDelay is not applied), so per-group order holds across retries.
  • Duplicate-detection queues (from options or the existing queue's settings): abandon immediately, because a scheduled copy reuses MessageId and would be discarded.
  • GroupId is validated before sending: required on session queues (QueueException), at most 128 characters (ArgumentException); the enqueued count is unaffected on failure.
  • Entries that are never settled are released once their lock has expired (with a 30s grace period), so they don't leak memory or session receivers.
  • A dequeue that checks once still opens a session (1s floor); accepting and receiving share one deadline.
  • Retry copies keep Subject/ContentType/ReplyTo/To, and their redeliveries count as attempts.
  • Behavior change: on session queues, an Enqueuing handler can no longer be the one that supplies a missing GroupId. Use the GroupId(...) resolver.

@niemyjski

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eca2270a89

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread README.md
@niemyjski
niemyjski merged commit fe003d1 into main Oct 14, 2026
3 checks passed
@niemyjski
niemyjski deleted the feature/queue-group-id branch October 14, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant