Skip to content

Fix Redis persistent lifetime startup - #17827

Merged
David Negstad (danegsta) merged 2 commits into
mainfrom
danegsta/fix-redis-persistent-lifetime
Jun 2, 2026
Merged

David Negstad (danegsta) merged 2 commits into
mainfrom
danegsta/fix-redis-persistent-lifetime

Conversation

@danegsta

Copy link
Copy Markdown
Member

Description

Redis persistent containers could deadlock before container creation when Redis TLS startup arguments resolved allocated endpoint ports. Those arguments configure the ports Redis listens on inside the container, so they should use endpoint target ports instead of public/allocated ports, which may differ and may not be available before a proxyless persistent container exists.

This updates Redis TLS startup arguments to use target-port bindings for both the primary TLS endpoint and secondary non-TLS endpoint. With this change, the reported AppHost shape starts Redis instead of waiting forever on endpoint allocation:

builder.AddRedis("redis")
       .WithLifetime(ContainerLifetime.Persistent);

Fixes: #17822

Validation:

  • dotnet test --project tests/Aspire.Hosting.Redis.Tests/Aspire.Hosting.Redis.Tests.csproj --no-launch-profile -- --filter-method "*.RedisWithCertificateUsesTargetPortsForCommandLineArgs" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • dotnet test --project tests/Aspire.Hosting.Redis.Tests/Aspire.Hosting.Redis.Tests.csproj --no-launch-profile -- --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"

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

Use Redis endpoint target ports for TLS startup arguments so container command-line evaluation does not wait for allocated public ports before the container exists.

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

github-actions Bot commented Jun 2, 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 -- 17827

Or

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

@danegsta
David Negstad (danegsta) marked this pull request as ready for review June 2, 2026 05:52
Copilot AI review requested due to automatic review settings June 2, 2026 05:52

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

Fixes a deadlock when a Redis container with TLS configured is started with ContainerLifetime.Persistent. The TLS startup arguments (--tls-port/--port) were resolving EndpointProperty.Port (the host-side allocated port), which is unavailable before the container exists in proxyless persistent mode, causing endpoint allocation to wait forever. Since these arguments configure ports inside the container, they must use EndpointProperty.TargetPort instead.

Changes:

  • Switch Redis TLS startup arg port references from EndpointProperty.Port to EndpointProperty.TargetPort for both primary (TLS) and secondary (non-TLS) endpoints.
  • Add a regression test (RedisWithCertificateUsesTargetPortsForCommandLineArgs) asserting the args resolve to the container target ports 6379/6380.

Reviewed changes

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

File Description
src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs Use EndpointProperty.TargetPort for --tls-port and --port Redis args.
tests/Aspire.Hosting.Redis.Tests/AddRedisTests.cs Adds test verifying TLS args use target ports under persistent lifetime.

Use a bounded wait around the Redis argument evaluation regression test so the test fails promptly if endpoint resolution deadlocks again.

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

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

❓ CLI E2E Tests unknown — 110 passed, 0 failed, 2 unknown (commit c122c70)

View all recordings
Status Test Recording Job Artifacts
✅ AddPackageInteractiveWhileAppHostRunningDetached Recording #79011027492 Logs
✅ AddPackageWhileAppHostRunningDetached Recording #79011027492 Logs
✅ AgentCommands_AllHelpOutputs_AreCorrect Recording #79011027167 Logs
✅ AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording #79011027167 Logs
✅ AgentInitCommand_MigratesDeprecatedConfig Recording #79011027167 Logs
✅ AgentInitCommand_NonInteractive_BundleOnlySkillsBeyondCliCatalog_AreInstallable Recording #79011027167 Logs
✅ AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording #79011027357 Logs
✅ AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording #79011027357 Logs
✅ AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording #79011027357 Logs
✅ AllPublishMethodsBuildDockerImages Recording #79011027445 Logs
✅ AspireAddAndStartWorkAgainstLegacyAppHostTs Recording #79011027395 Logs
✅ AspireAddPackageVersionToDirectoryPackagesProps Recording #79011027432 Logs
✅ AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording #79011027603 Logs
✅ AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles Recording #79011027459 Logs
❔ AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive Recording #79011027459 Logs
✅ AspireStartUpdatesStaleTypeScriptAppHostPath Recording #79011026940 Logs
✅ AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording #79011027432 Logs
✅ AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording #79011027432 Logs
✅ Banner_DisplayedOnFirstRun Recording #79011027305 Logs
✅ Banner_DisplayedWithExplicitFlag Recording #79011027305 Logs
✅ Banner_NotDisplayedWithNoLogoFlag Recording #79011027305 Logs
✅ CertificatesClean_RemovesCertificates Recording #79011027554 Logs
✅ CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording #79011027554 Logs
✅ CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording #79011027554 Logs
✅ ConfigSetGet_CreatesNestedJsonFormat Recording #79011027230 Logs
✅ CreateAndRunAspireStarterProject Recording #79011027376 Logs
✅ CreateAndRunAspireStarterProjectWithBundle Recording #79011027318 Logs
✅ CreateAndRunEmptyAppHostProject Recording #79011027470 Logs
✅ CreateAndRunJavaEmptyAppHostProject Recording #79011027251 Logs
✅ CreateAndRunJsReactProject Recording #79011027451 Logs
✅ CreateAndRunPolyglotAppHostWithDevLocalhostUrls Recording #79011027376 Logs
✅ CreateAndRunPythonReactProject Recording #79011027239 Logs
✅ CreateAndRunTypeScriptEmptyAppHostProject Recording #79011027489 Logs
✅ CreateAndRunTypeScriptStarterProject Recording #79011027483 Logs
✅ CreateJavaAppHostWithViteApp Recording #79011027579 Logs
✅ CreateTypeScriptAppHostWithViteApp_AllowsGuestAppPackageManagerToDiffer Recording #79011027342 Logs
✅ CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording #79011027342 Logs
✅ DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording #79011026831 Logs
✅ DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording #79011026831 Logs
✅ DashboardRunWithOtelTracesReturnsNoTraces Recording #79011026831 Logs
✅ DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording #79011026831 Logs
✅ DeployK8sBasicApiService Recording #79011027504 Logs
✅ DeployK8sWithExternalHelmChart Recording #79011027289 Logs
✅ DeployK8sWithGarnet Recording #79011027482 Logs
✅ DeployK8sWithMongoDB Recording #79011027178 Logs
✅ DeployK8sWithMySql Recording #79011027312 Logs
✅ DeployK8sWithPostgres Recording #79011027303 Logs
✅ DeployK8sWithRabbitMQ Recording #79011027392 Logs
✅ DeployK8sWithRedis Recording #79011027371 Logs
✅ DeployK8sWithSqlServer Recording #79011027105 Logs
✅ DeployK8sWithValkey Recording #79011027452 Logs
✅ DeployTypeScriptAppToKubernetes Recording #79011027430 Logs
✅ DescribeCommandResolvesReplicaNames Recording #79011027396 Logs
✅ DescribeCommandShowsRunningResources Recording #79011027396 Logs
✅ DetachFormatJsonProducesValidJson Recording #79011027326 Logs
✅ DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording #79011027326 Logs
✅ DoPublishAndDeployListStepsWork Recording #79011027045 Logs
✅ DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording #79011027355 Logs
✅ DoctorCommand_DetectsDeprecatedAgentConfig Recording #79011027167 Logs
✅ DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording #79011026929 Logs
✅ DoctorCommand_WithSslCertDir_ShowsTrusted Recording #79011026929 Logs
✅ DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording #79011026929 Logs
✅ GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording #79011027345 Logs
✅ GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording #79011027342 Logs
✅ GlobalMigration_HandlesCommentsAndTrailingCommas Recording #79011027230 Logs
✅ GlobalMigration_HandlesMalformedLegacyJson Recording #79011027230 Logs
✅ GlobalMigration_PreservesAllValueTypes Recording #79011027230 Logs
✅ GlobalMigration_SkipsWhenNewConfigExists Recording #79011027230 Logs
✅ GlobalSettings_MigratedFromLegacyFormat Recording #79011027230 Logs
✅ IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording #79011027345 Logs
✅ InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording #79011027342 Logs
✅ InteractiveCSharpInitCreatesExpectedFiles Recording #79011027098 Logs
✅ InvalidAppHostPathWithComments_IsHealedOnRun Recording #79011027308 Logs
✅ JavaScriptHostingApisRunFromTypeScriptAppHost Recording #79011027445 Logs
✅ LatestCliCanStartStableChannelAppHost Recording #79011027376 Logs
✅ LatestCliCanStartStableChannelTypeScriptAppHost Recording #79011027376 Logs
✅ LegacySettingsMigration_AdjustsRelativeAppHostPath Recording #79011026940 Logs
✅ LogsCommandShowsResourceLogs Recording #79011027367 Logs
✅ OtelLogsReturnsStructuredLogsFromStarterApp Recording #79011027224 Logs
✅ OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording #79011027224 Logs
✅ PsCommandListsRunningAppHost Recording #79011027201 Logs
✅ PsFormatJsonOutputsOnlyJsonToStdout Recording #79011027201 Logs
✅ PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording #79011027537 Logs
✅ PublishWithConfigureEnvFileUpdatesEnvOutput Recording #79011027537 Logs
✅ PublishWithDockerComposeServiceCallbackSucceeds Recording #79011027537 Logs
✅ PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording #79011027537 Logs
✅ ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries Recording #79011027192 Logs
✅ ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording #79011027192 Logs
✅ RestoreGeneratesSdkFiles Recording #79011027334 Logs
✅ RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording #79011027373 Logs
✅ RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording #79011027373 Logs
✅ RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording #79011027463 Logs
✅ RunFromParentDirectory_UsesExistingConfigNearAppHost Recording #79011027469 Logs
✅ RunReportsSyntaxErrorsForDotNetAppHost Recording #79011026951 Logs
✅ RunReportsSyntaxErrorsForTypeScriptAppHost Recording #79011026951 Logs
✅ SecretCrudOnDotNetAppHost Recording #79011027364 Logs
✅ SecretCrudOnTypeScriptAppHost Recording #79011027472 Logs
✅ StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording #79011027186 Logs
✅ StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording #79011027322 Logs
✅ StartReportsSyntaxErrorsForDotNetAppHost Recording #79011026951 Logs
✅ StartReportsSyntaxErrorsForTypeScriptAppHost Recording #79011026951 Logs
✅ StopAllAppHostsFromAppHostDirectory Recording #79011027365 Logs
✅ StopJavaPolyglotAppHostUsingApphostDirectory Recording #79011027480 Logs
✅ StopNonInteractiveSingleAppHost Recording #79011027365 Logs
✅ StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording #79011027307 Logs
✅ StopWithNoRunningAppHostExitsSuccessfully Recording #79011027492 Logs
✅ TypeScriptAppHostRunDoesNotDeadlockWhenLazyOptionsInvokeAsyncCallback Recording #79011027489 Logs
✅ UnAwaitedChainsCompileWithAutoResolvePromises Recording #79011027373 Logs
❔ UpdateProjectChannelToStable_CSharpEmptyAppHost_PreservesAspireConfigChannel Recording #79011027214 Logs
✅ UpdateProjectChannelToStable_CSharpSingleFileInit_PreservesAspireConfigChannel Recording #79011027214 Logs
✅ UpdateProjectChannelToStable_TypeScriptSingleFileInit_PreservesAspireConfigChannel Recording #79011027214 Logs
✅ UpdateProjectChannelToStable_TypeScript_PreviewsStablePackagesAndPreservesChannel Recording #79011027214 Logs

📹 Recordings uploaded automatically from CI run #26801455791

@danegsta

Copy link
Copy Markdown
Member Author

/backport to release/13.4

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Started backporting to release/13.4 (link to workflow run)

@danegsta
David Negstad (danegsta) merged commit 0ac9090 into main Jun 2, 2026
312 checks passed
@danegsta
David Negstad (danegsta) deleted the danegsta/fix-redis-persistent-lifetime branch June 2, 2026 21:05
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.5 milestone Jun 2, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redis integration fails to start container when lifetime is set to persistant

3 participants