Skip to content

Don't capture AsyncLocals into CancellationChangeToken registration#392

Merged
davidfowl merged 7 commits intodotnet:release/2.2from
benaadams:async-local
Aug 27, 2018
Merged

Don't capture AsyncLocals into CancellationChangeToken registration#392
davidfowl merged 7 commits intodotnet:release/2.2from
benaadams:async-local

Conversation

@benaadams
Copy link
Member

This causes a problem with IHttpContextAccessor as it captures the HttpContext and everything linked to it causing a lot of memory to become rooted (as seen in https://github.com/aspnet/KestrelHttpServer/issues/2840#issuecomment-416034872)

image

/cc @davidfowl

@davidfowl
Copy link
Member

@benaadams test?

Copy link
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

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

nits

public IDisposable RegisterChangeCallback(Action<object> callback, object state)
{
// Don't capture the current ExecutionContext and its AsyncLocals onto the token registration causing them to live forever
bool restoreFlow = false;
Copy link
Member

Choose a reason for hiding this comment

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

var

{
// Restore the current ExecutionContext
if (restoreFlow)
ExecutionContext.RestoreFlow();
Copy link
Member

Choose a reason for hiding this comment

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

ASP.NET coding standard is { } around a single line if statement.

Copy link
Member

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

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

I need to do some looking and see what this might break. But this change LGTM.

We should also ask for this API to be exposed in CoreCLR https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs#L255.

I'll file an API request for this.

var restoreFlow = false;
try
{
if (!ExecutionContext.IsFlowSuppressed())

Choose a reason for hiding this comment

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

Should this outside the if block? Doesn't really need a try-catch does it?

Copy link
Member Author

Choose a reason for hiding this comment

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

is the try finally its for, the catch was there previously

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved if outside

{
// AsyncLocal not set, when run on clean context
// A suppressed flow runs in current context, rather than restoring the captured context
Assert.Equal(0, ((AsyncLocal<int>) al).Value);

Choose a reason for hiding this comment

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

Might want to set something that verifies that this block of code was executed.

var executed = false;
...
     Assert.Equal(0, ((AsyncLocal<int>) al).Value);
     executed = true;
...

Assert.True(executed);

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, I like that :)

@pranavkm
Copy link

@davidfowl good to get this in?

@davidfowl
Copy link
Member

Yep

@davidfowl davidfowl merged commit 0f768ad into dotnet:release/2.2 Aug 27, 2018
@benaadams benaadams deleted the async-local branch September 25, 2018 00:17
@benaadams benaadams restored the async-local branch December 7, 2018 14:57
@benaadams benaadams deleted the async-local branch December 7, 2018 14:57
@benaadams benaadams restored the async-local branch December 7, 2018 14:57
@ghost ghost locked as resolved and limited conversation to collaborators May 30, 2023
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.

4 participants