Polyglot capability invocation gate: share it across integration-host connections, gate RunSyncOnBackgroundThread exports, and test async release
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 42/100
Research direction
Start with CapabilityDispatcher, RemoteHostServer, HandleRegistry, and the RunSyncOnBackgroundThread export flag; trace how the invocation gate is registered and used for both integration host connections and background thread exports. Then inspect the callback proxy tests and add coverage proving another gated invocation completes while an async export is awaiting a TaskCompletionSource. Done means shared builder mutations are gated and the async release behavior is covered without gating long-running exports such as run.
Written by the indexing model from the issue text.
Description
Follow-up from #21519 (Serialize synchronous capability invocations per polyglot guest connection). @sebastienros raised three non-blocking points in review. I checked each one against the PR head 17de5ac2, and all three need follow-up work.
1. The gate is per connection, but the builder is shared when integration hosts are enabled
CapabilityDispatchercreates its own gate (private readonly CapabilityInvocationGate _invocationGate = new();), andRemoteHostServerregisters the dispatcher as scoped.- When
integrationConfiguration.Enabledis set,RemoteHostServerregistersHandleRegistryas a singleton. Integration hosts then call builder APIs such asbuilder.addContainer(...)over their own connections, which means they go through a different dispatcher and a different gate. - Effect: if a guest leaves
addKafka(...)(forwarded to the host) andaddPostgres(...)un-awaited, the two calls can still overlap on the sharedList<IResource>andIServiceCollection. - Proposal: register
CapabilityInvocationGatein DI with the same lifetime rule asHandleRegistry(singleton when integration hosts are enabled, scoped otherwise) and inject it intoCapabilityDispatcher. External capabilities are forwarded before they reachInvokeMethodAsync, so a guest call doesn't hold the gate while the host re-enters.
2. Exports marked RunSyncOnBackgroundThread skip the gate
InvokeMethodAsyncreturns early withTask.Run(() => InvokeMethodCore(...))whenRunSyncOnBackgroundThreadis set, so those calls never take the gate.- That flag isn't limited to
run.AspireExportAnalyzerrecommends it for any export that invokes a synchronous delegate inline, so builder-mutating exports use it too. For example,MySqlBuilderExtensions.WithPhpMyAdminis[AspireExport(RunSyncOnBackgroundThread = true)]and callsResources.OfType<...>().SingleOrDefault()andAddResource(...). - Effect: an un-awaited
mysql.withPhpMyAdmin()alongside an un-awaitedaddContainer(...)can lose aList<IResource>add or throw "Collection was modified". This is a pre-existing issue onmain, not a regression from #21519. - Proposal: now that callback proxies release the gate, run these exports under the gate (
Task.Run(() => _invocationGate.RunAsync(() => InvokeMethodCore(...)))). Long-running exports such asrunmust stay ungated, so this needs a way to tell the two kinds apart, such as a separate attribute property or a dedicated opt-out.
3. No test asserts that the gate is released when an async export returns its Task
GateProbeis synchronous, and the re-entry tests release the gate through the callback proxy. These tests would still pass if a later change held the gate acrossUnwrapAsyncResultAsync. That change would hang the connection whenever an async export waits on another guest call.- Proposal: add a test with an async export that awaits a
TaskCompletionSource, and assert that a second gated invocation completes before the source is set.
🤖 Posted by AspireAgent (AI Agent)
- Dominant language
- C#
- Stars
- 6.4k
- Forks
- 1k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 349
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/aspire
-
Aspire.Hosting.Yarp flattens TimeSpan cluster settings (ActivityTimeout, health-check intervals) into per-property env vars the YARP container ignoresPossibly taken @itsrayeedscodespace claimed this 1 day ago. Openarea-integrations
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 2 days
-
Dashboard structured logs toolbar overlaps the resource name and wraps poorly in constrained layoutsOpenarea-dashboard
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 2 days
-
area-dashboard
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 2 days
-
area-dashboard
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 2 days
-
area-templates
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 2 days
All issues in microsoft/aspire
Similar issues
-
Assert.That on a null non-generic IEnumerable throws ArgumentNullException, so IsNull() cannot passOpenbug P2
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
area/automation area/sdk kind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
unoplatform/uno.templates#2406 ·
Maintainers usually reply within 1 day
-
bug frontend ui
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
agentic-workflows
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
documentation trivial
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day