Skip to content

Fix blocking ParameterResource.Value calls to prevent deadlocks in Aspire 9.4+ #763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 30, 2025

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Jul 28, 2025

This PR addresses blocking calls to ParameterResource.Value that can cause deadlocks in Aspire 9.4+ due to changes in dotnet/aspire#10354.

Problem

The recent changes in dotnet/aspire require migrating from synchronous ParameterResource.Value calls to the asynchronous IValueProvider.GetValueAsync API. Blocking calls to .Value, especially in asynchronous pipeline methods, risk deadlocking or blocking app host startup.

Solution

Primary Fixes (DbGate Integration):

  • Replaced blocking .Value calls with deferred parameter resolution by passing ParameterResource instances directly to environment variables
  • This allows Aspire to resolve parameters asynchronously at runtime instead of blocking during configuration

Files Changed:

  • src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs
  • src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/SqlServerBuilderExtensions.cs
  • src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/MySqlBuilderExtensions.cs
  • src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/RedisBuilderExtensions.cs

Additional Fixes:

  • Fixed blocking call in ActiveMQ health check setup to use GetValueAsync
  • Fixed Minio environment variable configuration to use deferred resolution

Example of the fix:

// Before (blocking)
context.EnvironmentVariables.Add($"PASSWORD_postgres{counter}", postgresServer.PasswordParameter.Value);

// After (deferred resolution)
context.EnvironmentVariables.Add($"PASSWORD_postgres{counter}", postgresServer.PasswordParameter);

Outstanding Issues

Some configurations (Adminer JSON serialization, Dapr metadata) still use blocking calls due to architectural constraints requiring immediate string values in synchronous environment callbacks. These are documented for future investigation but are beyond the scope of the original issue which focused on async pipeline methods.

Fixes #751.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits July 28, 2025 02:09
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
@Copilot Copilot AI changed the title [WIP] Track migration from ParameterResource.Value to IValueProvider.GetValueAsync and eventing API due to changes in dotnet/aspire#10354 Fix blocking ParameterResource.Value calls to prevent deadlocks in Aspire 9.4+ Jul 28, 2025
@Copilot Copilot AI requested a review from aaronpowell July 28, 2025 02:22
Copilot finished work on behalf of aaronpowell July 28, 2025 02:22
@aaronpowell
Copy link
Member

aaronpowell commented Jul 28, 2025

@davidfowl is this looking like the right direction for a starting point? I assume that we'll need to have this updated for use 9.4 before the code will compile

@davidfowl
Copy link
Contributor

@copilot cast the ParameterResource instance to IValueProvider and then call GetValueAsync on it.

Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jul 28, 2025

@copilot cast the ParameterResource instance to IValueProvider and then call GetValueAsync on it.

Applied the IValueProvider cast pattern as requested. Updated ActiveMQ health check and all test assertions to use await ((IValueProvider)parameterResource).GetValueAsync(ct) instead of calling GetValueAsync directly on ParameterResource. Commit f16b0f3.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dnceng.pkgs.visualstudio.com
    • Triggering command: dotnet build src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ --no-restore (dns block)
    • Triggering command: dotnet build src/CommunityToolkit.Aspire.Hosting.ActiveMQ/ --no-restore --verbosity minimal (dns block)
    • Triggering command: dotnet build tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/ --no-restore --verbosity minimal (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Copilot Copilot AI requested a review from davidfowl July 28, 2025 02:59
Copilot finished work on behalf of davidfowl July 28, 2025 02:59
@davidfowl
Copy link
Contributor

@aaronpowell should be doable without referencing 9.4

@aaronpowell
Copy link
Member

@aaronpowell should be doable without referencing 9.4

Cool - wasn't sure if it was an API added to 9.4.

@davidfowl
Copy link
Contributor

It was but there's a way to go async pre 9.4 as well, at least in the calling pattern.

Copy link
Contributor Author

Copilot AI commented Jul 28, 2025

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dnceng.pkgs.visualstudio.com
    • Triggering command: dotnet build src/CommunityToolkit.Aspire.Hosting.Minio/ --no-restore --verbosity minimal (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Copilot Copilot AI requested a review from davidfowl July 28, 2025 03:38
Copilot finished work on behalf of davidfowl July 28, 2025 03:38
Copy link
Contributor Author

Copilot AI commented Jul 28, 2025

@copilot, look for ConfigureAdminerContainer in the source; there are multiple places where ParameterResource.Value is used.

You're correct - there are still blocking ParameterResource.Value calls in the ConfigureAdminerContainer methods across the database extensions. These are architectural constraints due to the JSON serialization requirement for ADMINER_SERVERS environment variable, which needs immediate string values rather than deferred parameter resolution.

These cases are different from the DbGate blocking calls that were the primary focus of the original issue. The environment callback context is synchronous and requires immediate values for JSON serialization. A proper fix would require changing the architecture to use an event-based async pattern instead of the sync environment callback.

Would you like me to attempt a refactor to use the async eventing pattern, or should these be documented as known limitations requiring future architectural changes?

Copilot finished work on behalf of Alirexaa July 28, 2025 07:22
@aaronpowell
Copy link
Member

@copilot search the codebase for any more references of ParameterResource.Value and ensure they are migrated too.

…c pattern

Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jul 29, 2025

@copilot search the codebase for any more references of ParameterResource.Value and ensure they are migrated too.

I've completed a comprehensive search and migration of all remaining ParameterResource.Value blocking calls in the codebase.

What was migrated:

  • All test files using .Value calls now use the async await ((IValueProvider)parameter).GetValueAsync(CancellationToken.None) pattern
  • Updated test methods to be async where needed
  • Added proper IValueProvider using statements to all affected test files

What remains (architectural constraints):

  • ConfigureAdminerContainer methods in database extensions: These use synchronous environment callbacks requiring immediate string values for JSON serialization
  • Dapr metadata extensions: Similar constraint requiring immediate values for metadata configuration

These remaining cases require architectural changes to move from synchronous environment callbacks to async eventing patterns, which is beyond the scope of the original deadlock issue. All async pipeline methods and test code now use the proper async patterns.

Commit cc185c9

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • dnceng.pkgs.visualstudio.com
    • Triggering command: dotnet build /home/REDACTED/work/Aspire/Aspire/tests/CommunityToolkit.Aspire.Hosting.MySql.Extensions.Tests/ --no-restore --verbosity minimal (dns block)
    • Triggering command: dotnet restore tests/CommunityToolkit.Aspire.Hosting.MySql.Extensions.Tests/ (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of aaronpowell July 29, 2025 05:23
@aaronpowell
Copy link
Member

@copilot revert that last change

Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jul 29, 2025

@copilot revert that last change

Reverted the test file migrations that converted ParameterResource.Value calls to async GetValueAsync pattern. All test files now use their original .Value usage. Commit 7eaf60d.

Copilot finished work on behalf of aaronpowell July 29, 2025 05:54
Copy link
Contributor

Code Coverage

Package Line Rate Branch Rate Complexity Health
CommunityToolkit.Aspire.EventStore 100% 100% 46
CommunityToolkit.Aspire.GoFeatureFlag 100% 97% 74
CommunityToolkit.Aspire.Hosting.ActiveMQ 80% 40% 100
CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit 1% 0% 14
CommunityToolkit.Aspire.Hosting.Adminer 73% 50% 20
CommunityToolkit.Aspire.Hosting.Azure.Dapr 66% 50% 832
CommunityToolkit.Aspire.Hosting.Azure.Dapr.Redis 97% 88% 36
CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder 100% 100% 22
CommunityToolkit.Aspire.Hosting.Bun 82% 71% 54
CommunityToolkit.Aspire.Hosting.Dapr 62% 51% 728
CommunityToolkit.Aspire.Hosting.DbGate 94% 50% 18
CommunityToolkit.Aspire.Hosting.Deno 84% 75% 72
CommunityToolkit.Aspire.Hosting.EventStore 94% 100% 18
CommunityToolkit.Aspire.Hosting.GoFeatureFlag 93% 50% 18
CommunityToolkit.Aspire.Hosting.Golang 87% 70% 28
CommunityToolkit.Aspire.Hosting.Java 69% 72% 120
CommunityToolkit.Aspire.Hosting.k6 58% 12% 20
CommunityToolkit.Aspire.Hosting.LavinMQ 78% 50% 18
CommunityToolkit.Aspire.Hosting.LavinMQ.MassTransit 1% 0% 14
CommunityToolkit.Aspire.Hosting.MailPit 91% 50% 14
CommunityToolkit.Aspire.Hosting.McpInspector 90% 48% 94
CommunityToolkit.Aspire.Hosting.Meilisearch 73% 57% 50
CommunityToolkit.Aspire.Hosting.Minio 93% 75% 48
CommunityToolkit.Aspire.Hosting.MongoDB.Extensions 96% 83% 36
CommunityToolkit.Aspire.Hosting.MySql.Extensions 100% 88% 76
CommunityToolkit.Aspire.Hosting.Ngrok 52% 35% 82
CommunityToolkit.Aspire.Hosting.NodeJS.Extensions 47% 52% 136
CommunityToolkit.Aspire.Hosting.Ollama 67% 70% 174
CommunityToolkit.Aspire.Hosting.PapercutSmtp 92% 50% 10
CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions 99% 88% 88
CommunityToolkit.Aspire.Hosting.Python.Extensions 68% 55% 90
CommunityToolkit.Aspire.Hosting.RavenDB 63% 49% 136
CommunityToolkit.Aspire.Hosting.Redis.Extensions 100% 71% 48
CommunityToolkit.Aspire.Hosting.Rust 94% 83% 16
CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects 76% 64% 154
CommunityToolkit.Aspire.Hosting.Sqlite 96% 89% 42
CommunityToolkit.Aspire.Hosting.SqlServer.Extensions 100% 85% 76
CommunityToolkit.Aspire.Hosting.SurrealDb 71% 54% 144
CommunityToolkit.Aspire.MassTransit.RabbitMQ 100% 100% 30
CommunityToolkit.Aspire.Meilisearch 97% 92% 68
CommunityToolkit.Aspire.Microsoft.Data.Sqlite 89% 85% 52
CommunityToolkit.Aspire.Microsoft.EntityFrameworkCore.Sqlite 50% 50% 88
CommunityToolkit.Aspire.Minio.Client 73% 59% 88
CommunityToolkit.Aspire.OllamaSharp 74% 69% 120
CommunityToolkit.Aspire.RavenDB.Client 60% 53% 237
CommunityToolkit.Aspire.SurrealDb 96% 90% 56
Summary 72% (7208 / 10055) 60% (2245 / 3766) 4505

Minimum allowed line rate is 60%

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.

Track migration from ParameterResource.Value to IValueProvider.GetValueAsync and eventing API due to changes in dotnet/aspire#10354
4 participants