Skip to content

Fix MAUI launch queue handoff and OTLP tunnels - #18591

Draft
Gerald Versluis (jfversluis) wants to merge 26 commits into
microsoft:mainfrom
jfversluis:jfversluis-maui-launch-queue
Draft

Fix MAUI launch queue handoff and OTLP tunnels#18591
Gerald Versluis (jfversluis) wants to merge 26 commits into
microsoft:mainfrom
jfversluis:jfversluis-maui-launch-queue

Conversation

@jfversluis

@jfversluis Gerald Versluis (jfversluis) commented Jul 1, 2026

Copy link
Copy Markdown
Member

Focused replacement PRs

This broad draft has been split into smaller reviewable changes:

The remaining DevTunnels watcher/reconciliation, Aspire.Hosting core/DCP lifecycle, readiness, Foundry, Dashboard, and playground work is intentionally not included in either focused PR.

Description

Fixes the MAUI platform launch queue so multiple targets for the same MAUI project keep serialized builds without blocking on apps that are already running.

Current main launched MAUI platform resources with dotnet build --no-restore /t:Run -p:NoBuild=true. SDK 10.0.201 rejects that shape with NETSDK1085 because the Build target is still invoked while NoBuild=true. This keeps the intended dotnet build /t:Run handoff while avoiding duplicate build work on platforms that can launch from the queued build output.

User-facing usage

Users can keep adding multiple MAUI platform resources for the same project. Builds are serialized, but Mac Catalyst, iOS, and Windows-style launch resources release the queue once DCP reports the launch process as running, so another platform can start building while the first app remains open. Android keeps the normal Run target because it performs deploy/runtime upload work after build, and releases the queue when that short-lived Run process exits.

var mauiApp = builder.AddMauiProject("mauiapp", "../MauiApp/MauiApp.csproj");

mauiApp.AddMacCatalystDevice();
mauiApp.AddiOSSimulator()
    .WithOtlpDevTunnel();
mauiApp.AddAndroidEmulator()
    .WithOtlpDevTunnel();

The change also hardens the related runtime lifecycle:

  • MAUI OTLP dev tunnels prefer the dashboard OTLP/HTTP endpoint, forward to the allocated listener port, preserve the resolved transport, reconcile listener changes, and fail clearly if DCP never publishes the concrete listener. Android and iOS regenerate their stable per-resource environment targets file on every restart so changed OTLP values are applied.
  • DevTunnel target watchers live until application shutdown, automatically retry failed reconciliation and stale-port cleanup, serialize shared port allocation, publish unknown access policy while refresh is unavailable, and clear synthetic health reports after recovery.
  • DCP executable Terminated is normalized to Aspire's existing Exited state. Completion waits pause only for DCP executable/container-exec Finished or Exited snapshots whose exit code is still pending; containers and custom resources without a future exit-code snapshot still complete deterministically.
  • Resource readiness is scoped to each replica generation. Staggered replicas and partial restarts receive matching ResourceReadyEvent callbacks, while stale callback and health-probe results cannot mark a newer generation ready.
  • Repeated Foundry Local ready events are serialized and idempotent: models download once, skip duplicate loads in the same service, and reload from the cached model after a service restart.

Validation:

  • ./build.sh --build /p:SkipNativeBuild=true /m:1 — succeeded with 0 warnings and 0 errors
  • Affected Hosting lifecycle test classes — 196 passed
  • Aspire.Hosting.DevTunnels.Tests — 64 passed
  • Aspire.Hosting.Maui.Tests — 200 passed
  • Aspire.Hosting.Foundry.Tests — 120 passed
  • TypeScript code generation tests — 99 passed
  • Targeted backchannel regression — 1 passed
  • Dashboard exited-state regression — 1 passed
  • ResourceHealthCheckServiceTests — 25 passed
  • Queued replica-generation regressions — 30 repeated runs, 60/60 test executions passed
  • Manual playground validation: Mac Catalyst entered Building while iOS remained Queued; iOS moved to Building after Mac reached Running; both then remained Running
  • Both non-Android launches used dotnet build --no-restore /t:Run -p:BuildDependsOn= -p:NoBuild=true with no NETSDK1085
  • The iOS app loaded five Weather API forecasts through the DevTunnel and exported dashboard OTLP logs, traces, and metrics
  • Final generic code review and Aspire architecture review reported no actionable findings
  • Exact-head CI at 201bc863e610cdb1658da676461fdf6cfb701c70: 334 successful jobs, 4 skipped, 0 failed

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18591

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18591"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes the MAUI platform launch queue so multiple targets for the same MAUI project keep serialized builds without blocking on already-running apps, and it repairs MAUI OTLP dev-tunnel telemetry. It also teaches the hosting and dashboard state model to recognize DCP's Terminated state so queued/building resources and terminal-host diagnostics release/wake correctly.

Changes:

  • Introduces KnownResourceStates.Terminated, adds it to TerminalStates/BuildableStates, and threads recognition of that state through wait-for-dependency logic, terminal-host diagnostics, and the dashboard (KnownResourceState.Terminated, IsStopped()).
  • Reworks the MAUI launch handoff: non-Android platforms launch with /t:Run -p:BuildDependsOn= -p:NoBuild=true and release the build lock on Running, while Android keeps /t:Run and holds the lock until its short-lived Run process exits (MauiBuildInfoAnnotation.ReleaseBuildLockOnResourceRunning).
  • Fixes MAUI OTLP dev-tunnel resolution to prefer the dashboard OTLP/HTTP endpoint, use the target listener port for tunnel forwarding, and set OTEL_EXPORTER_OTLP_PROTOCOL from the resolved endpoint transport.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Aspire.Hosting/ApplicationModel/CustomResourceSnapshot.cs Adds public Terminated state and includes it in TerminalStates/BuildableStates.
src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs Adds IsUnavailableState helper and Terminated handling in wait-for-dependency logic.
src/Aspire.Hosting/Lifecycle/TerminalHostFailureDiagnosticService.cs Replaces local terminal-state array with KnownResourceStates.TerminalStates.
src/Aspire.Dashboard/Model/KnownResourceState.cs Adds Terminated enum value.
src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs Treats Terminated as a stopped state.
src/Aspire.Hosting.Maui/MauiPlatformHelper.cs Branches launch args and build-lock release on Android vs. other platforms.
src/Aspire.Hosting.Maui/Annotations/MauiBuildInfoAnnotation.cs Adds ReleaseBuildLockOnResourceRunning flag.
src/Aspire.Hosting.Maui/Lifecycle/MauiBuildQueueEventSubscriber.cs Adds releaseOnRunning parameter and terminal-state-aware release logic.
src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs Prefers OTLP/HTTP endpoint, resolves target port, and sets OTLP protocol/transport.
src/Aspire.Hosting.Maui/Annotations/OtlpDevTunnelConfigurationAnnotation.cs Adds IsOtlpEndpointResolved/MarkOtlpEndpointResolved.
src/Aspire.Hosting.Maui/README.md Documents OTLP protocol selection and the DCP launch-handoff behavior.
tests/Aspire.Hosting.Maui.Tests/*, tests/Aspire.Hosting.Tests/*, tests/Aspire.Dashboard.Components.Tests/* Adds coverage for terminated-state handling, build-lock release, and OTLP resolution.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@adamint Adam Ratzman (adamint) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I found one MAUI OTLP tunnel issue and am checking whether I can push the focused fix.

Comment thread src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs
Comment thread src/Aspire.Hosting.Maui/MauiOtlpExtensions.cs Outdated
Copilot AI review requested due to automatic review settings July 1, 2026 23:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 16/16 changed files
  • Comments generated: 3
  • Review effort level: Low

Comment thread src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs Outdated
Comment thread src/Aspire.Hosting.Maui/Lifecycle/MauiBuildQueueEventSubscriber.cs Outdated
Copilot AI review requested due to automatic review settings July 2, 2026 01:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment thread src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Comment thread src/Aspire.Dashboard/Extensions/ResourceViewModelExtensions.cs Outdated
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings July 2, 2026 15:02
@jfversluis

Copy link
Copy Markdown
Member Author

Validation/review report for the latest push:

  • Removed the new public/dashboard Terminated state. Raw DCP ExecutableState.Terminated is now normalized to existing Aspire Exited at the DCP boundary.
  • Kept an internal-only snapshot marker for DCP-originated executable termination so terminal-host diagnostics do not report controller-initiated shutdown as a startup failure.
  • Applied the same normalization to both Executable and ContainerExec paths.
  • Preserved WaitForCompletion correctness: Finished/Exited without the expected exit code is not treated as successful completion.
  • Confirmed the temporary local debug/autoprobe validation hooks are not in the PR.

Local validation after the final changes:

dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class "*.ResourceSnapshotBuilderTests" --filter-class "*.TerminalHostFailureDiagnosticServiceTests" --filter-class "*.ResourceNotificationTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
dotnet test --project tests/Aspire.Hosting.Maui.Tests/Aspire.Hosting.Maui.Tests.csproj --no-launch-profile -- --filter-class "*.MauiBuildQueueTests" --filter-class "*.MauiPlatformExtensionsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
dotnet test --project tests/Aspire.Dashboard.Components.Tests/Aspire.Dashboard.Components.Tests.csproj --no-launch-profile -- --filter-class "*.ResourceViewModelExtensionsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
git diff --check

All passed. I also reran local code review and Aspire architecture review agents on the final local diff; both reported no findings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 20/20 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs Outdated
@jfversluis

Copy link
Copy Markdown
Member Author

Follow-up after CI: Hosting-3 initially exposed two existing WaitForCompletion integration tests that were still publishing Finished without an exit code. Since this PR intentionally treats terminal states without the expected exit code as unsuccessful completion, I updated those tests to publish ExitCode = 0. The Docker-backed tests cannot run in my local environment because Docker is unavailable, but the non-Docker focused suites passed locally and the full PR CI is now green.

@jfversluis

Copy link
Copy Markdown
Member Author

Adam Ratzman (@adamint) Ella Hathaway (@ellahathaway) The latest rebased head (254d8c9998) is mergeable and the review threads are resolved, but GitHub has not enqueued the pull_request workflows after the fork force-push (reopening the PR also did not enqueue them). Only CLA is registered and the required Final Results check remains expected. Could one of you retrigger or approve CI for this head? Local validation is clean: full build (0 warnings/errors), 220 affected Hosting tests, 197 MAUI tests, 64 DevTunnel tests, and the dashboard regression.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (4)

src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs:741

  • Inside the retry pipeline, the watcher loop uses the outer cancellationToken instead of the per-attempt ct passed to ExecuteAsync. This can prevent a failed attempt from being cleanly canceled between retries (and may keep WatchAsync alive longer than intended). Use the ct passed into the pipeline delegate when calling WatchAsync (and for downstream awaits that should be scoped to the attempt).
                await foreach (var resourceEvent in notifications.WatchAsync(cancellationToken).ConfigureAwait(false))
                {
                    var matchingPorts = tunnelResource.Ports
                        .Where(port => ReferenceEquals(port.TargetEndpoint.Resource, resourceEvent.Resource))
                        .ToArray();

src/Aspire.Hosting.DevTunnels/DevTunnelResource.cs:66

  • The watcher CTS is canceled and disposed immediately, but the watcher task is not awaited. Disposing a CancellationTokenSource while consumers may still be registering/awaiting on its token can surface ObjectDisposedException in unrelated code paths. Consider canceling without disposing until the watcher task has observed cancellation (e.g., keep a reference to the watcher Task and dispose in a continuation), or avoid disposing CTS instances that are only used for cancellation signaling.
    internal CancellationTokenSource ResetTargetEndpointWatcher(CancellationToken cancellationToken)
    {
        lock (_targetEndpointWatcherLock)
        {
            _targetEndpointWatcherCts?.Cancel();
            _targetEndpointWatcherCts?.Dispose();
            _targetEndpointWatcherCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            return _targetEndpointWatcherCts;
        }
    }

    internal void StopTargetEndpointWatcher()
    {
        lock (_targetEndpointWatcherLock)
        {
            _targetEndpointWatcherCts?.Cancel();
            _targetEndpointWatcherCts?.Dispose();
            _targetEndpointWatcherCts = null;
        }
    }

src/Aspire.Hosting.DevTunnels/DevTunnelHealthCheck.cs:107

  • QueueTunnelAndPortRefresh schedules a new Task.Run for each health check invocation without any in-flight deduplication. Under frequent health checks or slow network responses, this can lead to overlapping refreshes and increased load on the devtunnel CLI/API (and threadpool churn), even with the 2s timeout. Consider adding a simple gate (e.g., Interlocked/SemaphoreSlim) per tunnel to ensure only one refresh runs at a time, and coalesce subsequent requests.
        return Task.Run(async () =>
        {
            try
            {
                using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                timeoutCts.CancelAfter(s_refreshTimeout);

                var tunnelAccessStatus = await devTunnelClient.GetAccessAsync(tunnelResource.ResolvedTunnelId, portNumber: null, logger, timeoutCts.Token).ConfigureAwait(false);
                tunnelResource.LastKnownAccessStatus = tunnelAccessStatus;

                foreach (var portResource in tunnelResource.Ports)
                {
                    int? tunnelPort = null;
                    try
                    {
                        tunnelPort = await portResource.GetTunnelPortAsync(timeoutCts.Token).ConfigureAwait(false);
                        var portAccessStatus = await devTunnelClient.GetAccessAsync(tunnelResource.ResolvedTunnelId, tunnelPort, logger, timeoutCts.Token).ConfigureAwait(false);

                        if (portResource.ActiveTunnelPort is null || portResource.ActiveTunnelPort == tunnelPort)
                        {
                            portResource.LastKnownAccessStatus = portAccessStatus;
                        }
                    }

src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs:1166

  • IndexOf('.') can return -1 if the tunnel host does not contain a dot (e.g., unexpected host formats or test doubles), which will throw during slicing. Guard against hostPrefixLength <= 0 and either skip adding the Inspect URL or fall back to a safer transformation.
    private static Uri CreateInspectUri(Uri portUri)
    {
        // If tunnel host is sdfdff-3456.usw.devtunnels.ms, the inspect host is sdfdff-3456-inspect.usw.devtunnels.ms
        var hostPrefixLength = portUri.Host.IndexOf('.');
        var hostPrefix = portUri.Host[..hostPrefixLength];
        var hostSuffix = portUri.Host[hostPrefixLength..];
        return new UriBuilder(portUri) { Host = $"{hostPrefix}-inspect{hostSuffix}" }.Uri;
    }
  • Files reviewed: 33/33 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (3)

src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs:161

  • ExecutableStatus.ExitCode can use Conventions.UnknownExitCode when the code has not arrived yet. Keeping that sentinel as -1 causes completion waits to yield immediately and fail instead of waiting for the real exit-code snapshot. Normalize it to null, matching the container conversion above.
        var exitCode = executable.Status?.ExitCode;

src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs:105

  • ContainerExecStatus.ExitCode may be Conventions.UnknownExitCode while the real code is unavailable (as documented on that model). Preserving -1 here makes HasPendingDcpExitCode false and lets WaitForCompletion treat the placeholder as a real mismatching exit code. Normalize the sentinel to null, as the container snapshot path already does.

This issue also appears on line 161 of the same file.

        var exitCode = executable.Status?.ExitCode;

src/Aspire.Hosting/Health/ResourceHealthCheckService.cs:77

  • This later-generation readiness path is still guarded by the exact state == KnownResourceStates.Running comparison above (and monitor teardown uses an exact terminal-state lookup). ResourceNotificationService now recognizes states such as "running" case-insensitively and advances their generation, but the health service ignores those snapshots, so it never starts/fires readiness for that generation. Use the resource-state comparer for the outer Running and terminal checks as well.
                    else if (!resourceEvent.Resource.TryGetAnnotationsIncludingAncestorsOfType<HealthCheckAnnotation>(out _))
                    {
                        // Resources without health checks finish their monitor after the first ready
                        // event, so a later replica generation must trigger readiness from this loop.
                        FireResourceReadyEvent(state);
  • Files reviewed: 33/33 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs Outdated
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6cc2c61d-a000-410e-ae07-0d6482c410b7
Copilot AI review requested due to automatic review settings August 7, 2026 00:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (1)

src/Aspire.Hosting/Health/ResourceHealthCheckService.cs:193

  • A stale health probe can still mark a newer process generation ready. IsHealthCheckGenerationCurrent releases the state lock before this call, so a restart can increment _readyGenerationSignalVersion in between; FireResourceReadyEvent then captures the new running generation and publishes readiness using the old probe result. Pass the expected signal version into target capture and reject it atomically under the same lock (and similarly avoid publishing the stale health report).
                    FireResourceReadyEvent(state);
  • Files reviewed: 34/34 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs Outdated
Ensure delayed DCP exit codes, DevTunnel reconciliation, MAUI restart configuration, and Foundry Local reloads remain correct across repeated resource generations.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6cc2c61d-a000-410e-ae07-0d6482c410b7

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 42/42 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Reconcile replica generations directly from notification state before accepting health-check results so a queued restart cannot inherit readiness from an older check. Add deterministic coverage for notification-store updates that arrive before the health-monitor watcher.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6cc2c61d-a000-410e-ae07-0d6482c410b7
Copilot AI review requested due to automatic review settings August 7, 2026 21:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (1)

src/Aspire.Hosting.DevTunnels/DevTunnelHealthCheck.cs:46

  • This periodic health path no longer updates the published access-policy property. After the initial QueuePortRefresh succeeds and exits, a later GetAccessAsync failure here only clears LastKnownAccessStatus; the port snapshot keeps the old “Anonymous access” value, gets no synthetic unhealthy report, and receives no retry until unrelated endpoint reconciliation occurs. Route periodic port refreshes through the notification-aware retry path (or otherwise publish Unknown/health and retry) so the dashboard cannot retain stale access policy.
            _ = DevTunnelAccessStatusRefresh.QueueTunnelAndPortRefresh(_devTunnelClient, _tunnelResource, logger, cancellationToken);
  • Files reviewed: 42/42 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@jfversluis
Gerald Versluis (jfversluis) marked this pull request as draft August 10, 2026 09:55
@jfversluis

Copy link
Copy Markdown
Member Author

Marking this PR as draft because I let the scope creep beyond the original MAUI launch/build queue fix while addressing issues found during validation and review.

The additional fixes are valid and the branch is green, but combining MAUI queue handoff, OTLP/DevTunnel lifecycle, global DCP/wait semantics, replica readiness generations, and Foundry restart behavior made this PR much broader than it should be.

I am preserving this branch as a validated reference and replacing it with smaller, focused changes. The first replacement will contain only the minimum MAUI queue functionality: the corrected dotnet build /t:Run command shapes, Android versus non-Android queue handoff, focused tests, and documentation. The remaining fixes will be evaluated independently as follow-up PRs.

Please do not merge this PR in its current form.

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.

5 participants