Fix Dapr client startup deadlock in distributed deployment#713
Draft
Fix Dapr client startup deadlock in distributed deployment#713
Conversation
… to StartedAsync Co-authored-by: sven-n <5238610+sven-n@users.noreply.github.com> Agent-Logs-Url: https://github.com/MUnique/OpenMU/sessions/b9f6bd43-e155-4f43-ad0d-a5b304a95c1b
Copilot
AI
changed the title
[WIP] Fix Dapr client fail to start at first chance
Fix Dapr client startup deadlock in distributed deployment
Mar 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Service hosts blocked on
WaitForUpdatedDatabaseAsync()before callingapp.Run(), creating a circular dependency: the Dapr sidecar won't initialize its secret store until the app responds on port 8080, but port 8080 only opens afterapp.Run(), which requires secrets from Dapr.Root Cause
The startup sequence was: get DB secrets → wait for DB ready →
app.Run(). Dapr sidecar health-checks port 8080 to initialize, so secrets were never retrievable on first start.Fix
Leverage
IHostedLifecycleService.StartedAsync(.NET 8+), which fires after the HTTP server is listening. This decouples "HTTP API available" from "game servers ready":Key Changes
Extensions.cs— AddsWaitForDatabaseInitializationAsync(IServiceProvider, CancellationToken)for use insideStartedAsync, awaiting both the secretsInitializationtask andPersistenceContextProvider.WaitForUpdatedDatabaseAsync.ConnectServerHostedServiceWrapper,GameServerHostedServiceWrapper— Converted fromIHostedServicetoIHostedLifecycleService. Constructors now acceptIServiceProvider(no DB-dependent injection at construction time); actual initialization and server start deferred toStartedAsync.ManagableServerStatePublisher— Similarly converted;IManageableServerresolved lazily via a dedicatedInitializeServerAsyncloop within the heartbeat task, preventing duplicate event subscriptions and avoiding DB access at construction.ChatServerHostedServiceWrapper(new) — Replaces the anonymous factory lambda that eagerly resolvedChatServerDefinitionat host startup; initialization deferred toStartedAsync.**/Program.cs(ConnectServer, GameServer, ChatServer, FriendServer, GuildServer) — Replaces the blockingWaitForUpdatedDatabaseAsync()call beforeapp.Run()with the non-blockingWaitForDatabaseConnectionInitializationAsync()(which merely starts the background secrets-fetch task and sets upConnectionConfigurator).Original prompt
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.