Skip to content

Optimizes Service Bus admin API concurrency and auto-refresh#86

Merged
soliktomasz merged 3 commits intomainfrom
codex/performance-audit-remediation
Apr 10, 2026
Merged

Optimizes Service Bus admin API concurrency and auto-refresh#86
soliktomasz merged 3 commits intomainfrom
codex/performance-audit-remediation

Conversation

@soliktomasz
Copy link
Copy Markdown
Owner

@soliktomasz soliktomasz commented Apr 10, 2026

Improves application performance and stability by implementing two key optimizations:

  • Bounds Service Bus admin API concurrency: Introduces a new utility to limit the number of simultaneous Service Bus administrative calls (e.g., fetching queue or topic runtime properties). This reduces the load on Azure Service Bus, prevents potential throttling, and ensures the order of results is preserved.
  • Prevents overlapping auto-refresh cycles: Modifies the auto-refresh mechanism to ensure that new refresh operations (including message loading and alert evaluations) do not start if a previous refresh is still in progress. This avoids redundant work and stabilizes the application's background processes.

These changes are supported by new unit tests validating the bounded concurrency and the non-overlapping refresh logic.

Summary by CodeRabbit

  • Bug Fixes

    • Prevents overlapping auto-refresh operations to improve reliability
    • Improves dead-letter view toggling to avoid redundant reloads and race conditions
    • Applies bounded concurrency for admin operations (queues, topics, subscriptions) to reduce resource contention
  • Tests

    • Added unit tests validating concurrency limits, ordering, and auto-refresh/dead-letter behavior

- Introduce `BoundedAdminProjector` to throttle parallel metadata requests to Service Bus, preventing resource exhaustion when fetching entity details.
- Implement an interlocked gate in `MainWindowViewModel` to ensure auto-refresh ticks do not overlap.
- Remove redundant message loading when toggling the dead-letter view to prevent duplicate API calls.
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a new BoundedAdminProjector utility to run async projections with bounded concurrency, updates admin retrieval to use it, refactors MainWindowViewModel to prevent overlapping auto-refresh and coordinate dead-letter reloads, and adds tests validating concurrency and ordering behavior.

Changes

Cohort / File(s) Summary
Bounded Concurrency Utility
BusLane/Services/ServiceBus/BoundedAdminProjector.cs
New internal static class with SelectAsync<TSource,TResult> and ProjectAsync using SemaphoreSlim to limit concurrent projector executions (default max 8) while preserving input ordering.
Connection Operations Integration
BusLane/Services/ServiceBus/ConnectionStringOperations.cs
Replaced unbounded per-entity parallelization with BoundedAdminProjector.SelectAsync in GetQueuesAsync, GetTopicsAsync, GetSubscriptionsAsync; added AdminProjectionConcurrencyLimit accessor.
Auto-Refresh & Dead-Letter Coordination
BusLane/ViewModels/MainWindowViewModel.cs
Added _autoRefreshTickInProgress and _suppressDeadLetterReload fields; refactored timer to fire-and-forget HandleAutoRefreshTickAsync with reentrancy control; changed ToggleDeadLetterViewAsync to suppress immediate reload and use ReloadMessagesForDeadLetterAsync / TriggerDeadLetterReloadIfNeeded.
ServiceBus Operations Tests
BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs
Added two tests invoking non-public SelectAsync via reflection: one verifies max concurrency observed (18 items, max 3), another verifies source-order preservation under out-of-order completion (max 2). Includes reflection helper and CAS UpdateMaxValue.
MainWindowViewModel Tests
BusLane.Tests/ViewModels/MainWindowViewModelTests.cs
Added tests for dead-letter toggle single-load and skipping overlapping alert evaluations. Added test helpers: CreateConnectedQueueTab, UpdateMaxValue (atomic max), and InvokeHandleAutoRefreshTickAsync (reflective invocation). Updated CreateSut to accept optional IAlertService.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant Bounded as BoundedAdminProjector
    participant Gate as SemaphoreSlim
    participant Projector as Projector Func
    participant Results as Results Array

    Caller->>Bounded: Call SelectAsync(source, projector, maxConcurrency)
    Bounded->>Gate: init SemaphoreSlim(min(maxConcurrency, count))
    loop schedule one task per source item
        Caller->>Bounded: enqueue ProjectAsync(item, index)
    end
    par up to maxConcurrency
        Bounded->>Gate: await WaitAsync(ct)
        activate Projector
        Projector->>Projector: execute projector(item, ct)
        Projector-->>Results: store result[index]
        deactivate Projector
        Gate->>Gate: Release()
    end
    Bounded->>Caller: Task.WhenAll completes -> return ordered Results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through semaphores to keep things neat,

With slots to guard each busy little feat.
Dead letters paused while toggles took their turn,
Ticks no longer clash — concurrency we learn.
Order kept, async danced — a rabbit's cheerful beat.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main changes: optimizing Service Bus admin API concurrency via BoundedAdminProjector and improving auto-refresh coordination in MainWindowViewModel.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 codex/performance-audit-remediation

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
BusLane.Tests/Services/ServiceBus/ServiceBusOperationsFactoryTests.cs (1)

27-41: These tests pin an implementation detail, not the factory contract.

ServiceBusOperationsFactory already returns fixed concrete types in BusLane/Services/ServiceBus/ServiceBusOperationsFactory.cs:40-62, so these assertions only prove that two reflected static properties currently match. They will still pass if the returned types stop using BoundedAdminProjector, and they will fail if the two implementations ever need different budgets for valid reasons. Prefer keeping factory tests focused on the returned type and keeping concurrency-budget verification with BoundedAdminProjector/operations behavior tests instead.

Also applies to: 106-124, 147-155

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@BusLane.Tests/Services/ServiceBus/ServiceBusOperationsFactoryTests.cs` around
lines 27 - 41, The test is asserting a reflected static concurrency-limit
implementation detail instead of the factory contract; update the
ServiceBusOperationsFactory.CreateFromConnectionString test to assert the
concrete returned type (e.g., that factory.CreateFromConnectionString(...)
returns an instance of AzureCredentialOperations or the expected concrete class)
rather than comparing GetAdminProjectionConcurrencyLimit values, and move any
concurrency-budget verification into tests that exercise BoundedAdminProjector
or the specific operations behavior; apply the same change pattern to the other
similar tests referenced (the other CreateFromConnectionString and
CreateFromCredential tests).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs`:
- Around line 21-31: The inline projector passed to
InvokeBoundedAdminProjectorAsync can skip Interlocked.Decrement(ref
activeWorkers) if an exception or cancellation occurs, inflating activeWorkers
and invalidating concurrency assertions; wrap the increment/decrement around a
try/finally in the lambda so that Interlocked.Decrement(ref activeWorkers)
always runs (use try { await Task.Delay(..., ct); return item * 2; } finally {
Interlocked.Decrement(ref activeWorkers); }) and keep UpdateMaxValue(ref
maxConcurrentWorkers, inFlight) immediately after Interlocked.Increment to
preserve the max-tracking behavior.

In `@BusLane.Tests/ViewModels/MainWindowViewModelTests.cs`:
- Around line 329-330: The test in MainWindowViewModelTests currently uses
Task.Delay(TimeSpan.FromMilliseconds(2600)) which is brittle; replace the
wall-clock sleep with a deterministic trigger: inject a controllable/fake timer
or scheduler (e.g., a TestScheduler or an ITimer stub used by
MainWindowViewModel) and advance it twice to simulate two ticks, or modify the
stubbed alert evaluation (e.g., your EvaluateAlertsAsync stub) to complete a
TaskCompletionSource when the second evaluation occurs and await that signal
instead of sleeping; then perform the assertions immediately after advancing the
fake timer or awaiting the TCS.
- Around line 255-257: Replace the brittle Task.Delay(50) in the test with a
TaskCompletionSource that the PeekMessagesAsync stub completes when it runs:
modify the test to create a TaskCompletionSource (tcs), inject that tcs into the
PeekMessagesAsync stub implementation (the stub used by
ToggleDeadLetterViewCommand.ExecuteAsync) so that when PeekMessagesAsync is
invoked it calls tcs.SetResult(null) (or appropriate result), then await
tcs.Task after executing sut.ToggleDeadLetterViewCommand.ExecuteAsync(null)
instead of Task.Delay; this ensures the assertion runs only after the
fire-and-forget reload (PeekMessagesAsync) has completed.

In `@BusLane/ViewModels/MainWindowViewModel.cs`:
- Around line 1275-1278: ToggleDeadLetterViewAsync currently flips
CurrentNavigation.ShowDeadLetter and returns immediately while the actual reload
runs via FireAndForget in the property's change handlers, losing
AsyncRelayCommand tracking; fix it by invoking and awaiting the real reload task
directly inside ToggleDeadLetterViewAsync instead of returning
Task.CompletedTask and instead of relying on FireAndForget (e.g., after toggling
CurrentNavigation.ShowDeadLetter call the same reload method the property-change
handler uses, await that Task, and remove/avoid the FireAndForget path so
AsyncRelayCommand observes execution/errors).
- Around line 1652-1655: Do not reopen the auto-refresh gate during teardown:
remove the Interlocked.Exchange(ref _autoRefreshTickInProgress, 0) calls in the
dispose/teardown paths (references: _autoRefreshTimer,
_autoRefreshTickInProgress) so the gate remains closed, and ensure
HandleAutoRefreshTickAsync checks the _disposed flag at its start and
short-circuits immediately if _disposed is true; apply the same change for the
similar block around the other dispose/unsubscribe area (the block noted at
lines 1676-1679).

---

Nitpick comments:
In `@BusLane.Tests/Services/ServiceBus/ServiceBusOperationsFactoryTests.cs`:
- Around line 27-41: The test is asserting a reflected static concurrency-limit
implementation detail instead of the factory contract; update the
ServiceBusOperationsFactory.CreateFromConnectionString test to assert the
concrete returned type (e.g., that factory.CreateFromConnectionString(...)
returns an instance of AzureCredentialOperations or the expected concrete class)
rather than comparing GetAdminProjectionConcurrencyLimit values, and move any
concurrency-budget verification into tests that exercise BoundedAdminProjector
or the specific operations behavior; apply the same change pattern to the other
similar tests referenced (the other CreateFromConnectionString and
CreateFromCredential tests).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 93c89c8a-fc01-4657-8209-5de4c39d668a

📥 Commits

Reviewing files that changed from the base of the PR and between c26b660 and d97b619.

📒 Files selected for processing (7)
  • BusLane.Tests/Services/ServiceBus/ServiceBusOperationsFactoryTests.cs
  • BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs
  • BusLane.Tests/ViewModels/MainWindowViewModelTests.cs
  • BusLane/Services/ServiceBus/AzureCredentialOperations.cs
  • BusLane/Services/ServiceBus/BoundedAdminProjector.cs
  • BusLane/Services/ServiceBus/ConnectionStringOperations.cs
  • BusLane/ViewModels/MainWindowViewModel.cs

- Prevent redundant message reloads when toggling the dead-letter view by implementing a suppression flag.
- Add disposal checks to `HandleAutoRefreshTickAsync` to prevent background processing on closed tabs.
- Simplify Service Bus operation classes by removing redundant internal concurrency limit properties.
- Replace fragile `Task.Delay` calls in unit tests with `TaskCompletionSource` to ensure deterministic execution and reduce flakiness.
- Ensure concurrency counters in tests are correctly decremented using `try-finally` blocks.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs (1)

3-8: ⚠️ Potential issue | 🟡 Minor

Reorder the using block to keep System.* imports first.

System.Reflection should be grouped with the standard-library imports, ahead of BusLane.* and third-party namespaces.

As per coding guidelines, "Order using directives as: System/standard imports → BusLane imports → third-party imports (Avalonia, CommunityToolkit, Serilog, etc.)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs` around lines
3 - 8, Move the System namespace import so standard-library usings appear first:
reorder the using block in ServiceBusOperationsTests (where
ServiceBusOperationsTests class is defined) to place System.Reflection
immediately after other System usings (i.e., put System.* imports before
BusLane.* and third-party usings such as Azure.Messaging.ServiceBus,
BusLane.Services.ServiceBus, FluentAssertions, NSubstitute, and Xunit) to match
the project's using-directive ordering convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs`:
- Around line 21-37: The test uses Task.Delay which makes concurrency
nondeterministic; replace the timer-driven work lambda passed to
InvokeBoundedAdminProjectorAsync with a TaskCompletionSource-based coordination:
create a list/array of TaskCompletionSource for each input item, have the worker
increment Interlocked activeWorkers and call UpdateMaxValue, then await the
per-item tcs.Task instead of Task.Delay so you can deterministically control
when each item completes; in the test drive signal the first N tcs (N =
maxConcurrency, here 3) to allow workers to enter and assert
maxConcurrentWorkers reached 3, then release remaining tcs in input order to
assert outputs preserve source order; reference the existing
InvokeBoundedAdminProjectorAsync invocation, the activeWorkers/UpdateMaxValue
usage and the maxConcurrency parameter when making the change.

---

Outside diff comments:
In `@BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs`:
- Around line 3-8: Move the System namespace import so standard-library usings
appear first: reorder the using block in ServiceBusOperationsTests (where
ServiceBusOperationsTests class is defined) to place System.Reflection
immediately after other System usings (i.e., put System.* imports before
BusLane.* and third-party usings such as Azure.Messaging.ServiceBus,
BusLane.Services.ServiceBus, FluentAssertions, NSubstitute, and Xunit) to match
the project's using-directive ordering convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 00b40c11-03e4-4f21-887e-187b4f9d96dd

📥 Commits

Reviewing files that changed from the base of the PR and between d97b619 and 53c11d3.

📒 Files selected for processing (4)
  • BusLane.Tests/Services/ServiceBus/ServiceBusOperationsTests.cs
  • BusLane.Tests/ViewModels/MainWindowViewModelTests.cs
  • BusLane/Services/ServiceBus/ConnectionStringOperations.cs
  • BusLane/ViewModels/MainWindowViewModel.cs
🚧 Files skipped from review as they are similar to previous changes (2)
  • BusLane/ViewModels/MainWindowViewModel.cs
  • BusLane.Tests/ViewModels/MainWindowViewModelTests.cs

- Replace `Task.Delay` with `TaskCompletionSource` to precisely control and verify worker concurrency.
- Release workers in batches to ensure the concurrency limit is respected throughout the operation.
- Prevent potential test hangs by adding timeouts to asynchronous waits.
@soliktomasz soliktomasz merged commit 859af3d into main Apr 10, 2026
3 of 4 checks passed
@soliktomasz soliktomasz deleted the codex/performance-audit-remediation branch April 10, 2026 17:38
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