Skip to content
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

ResourceNotificationService.WatchAsync is not thread safe #4606

Closed
afscrome opened this issue Jun 20, 2024 · 3 comments
Closed

ResourceNotificationService.WatchAsync is not thread safe #4606

afscrome opened this issue Jun 20, 2024 · 3 comments
Labels
area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication
Milestone

Comments

@afscrome
Copy link
Contributor

afscrome commented Jun 20, 2024

If multiple consumers call ResourceNotificationService.WatchAsync in parallel, it looks like some of the subscriptions get lost.

Context in which I encountered this - I've been hitting a intermittent deadlocks (roughly 1 in 5 starts) with WaitForDependencies since I added my own listener to WatchAsync in which resources get stuck in the Waiting state indefinitely. WaitForDependenciesRunningHook makes it's call to WatchAsync during Task.Run, and I believe that can get delayed long enough to conflict with my own WatchAsync call in a different IDistributedApplicationLifecycleHook.

https://github.com/davidfowl/WaitForDependenciesAspire/blob/22e32d218943bd3b15e85c2f04e6415acff6054f/WaitForDependencies.Aspire.Hosting/WaitForDependenciesExtensions.cs#L146

image

I suspect the root problem is due to the following not being thread safe:

Repro Code:

int watchers = 0;
int executions = 0;
async Task Watch()
{
    await Task.Yield();
    var asyncEnumerable = notificationService.WatchAsync(default);
    Interlocked.Increment(ref watchers);
    await foreach (var item in asyncEnumerable)
    {
        Interlocked.Increment(ref executions);
        break;
    }
}

var tasks = Enumerable.Range(0, 100).Select(x => Watch()).ToArray();
await Task.Delay(TimeSpan.FromSeconds(1));
await notificationService.PublishUpdateAsync(resource, state => state with { Properties = state.Properties.Add(new("A", "value")) });
await Task.Delay(TimeSpan.FromSeconds(2));

Console.WriteLine($"Watchers: {watchers}");
Console.WriteLine($"Executions: {executions}");

class CustomResource(string name) : Resource(name),
    IResourceWithEnvironment,
    IResourceWithConnectionString,
    IResourceWithEndpoints
{
    public ReferenceExpression ConnectionStringExpression =>
        ReferenceExpression.Create($"CustomConnectionString");
}

Expected Results:

Watchers: 100
Executions: 100

Actual Results

Watchers: 100
Executions: 75

(Execution number varies from run to run, but is always below 100.)

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication label Jun 20, 2024
@mitchdenny mitchdenny added the bug label Jun 23, 2024
@mitchdenny mitchdenny added this to the 8.1 milestone Jun 23, 2024
@mitchdenny mitchdenny modified the milestones: 8.1, Backlog Jul 15, 2024
@mitchdenny
Copy link
Member

Putting this on the backlog for now. It isn't clear whether this is an issue with WaitForDependencies or soemthing inside the AppModel. When we get around to doing WaitForDependencies within the main tree itself then we can watch out for this.

@afscrome
Copy link
Contributor Author

@mitchdenny the repro code above doesn’t use WaitForDependencies, only the app model. I actually derived the repo from one of the existing unit tests for ResourceNotificationService.

The repo spawns 100 concurrent tasks that all call notificationService.WatchAsync. When PublishUpdateAsync is called, only some of the subscribers get updates.

@davidfowl davidfowl modified the milestones: Backlog, 9.0 Sep 16, 2024
@davidfowl
Copy link
Member

Fixed in #5515

@github-actions github-actions bot locked and limited conversation to collaborators Oct 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication
Projects
None yet
Development

No branches or pull requests

3 participants