Azure / Azure/DotNetty

Avoid capture AsyncLocal<T>/CallContext.LogicalData to DotNetty's XThread?

Open
#419 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
4.3k
Forks
1k
PR merge metrics
No merged PRs in 30d

Description

That will makes them alive forever and may leak something (but lucky only once per `IEventLoopGroup`) when used with some other frameworks(an `HttpContext` in aspnet/aspnetcore for me).

An workaround is add some code to any caller for create DotNetty's `IEventLoopGroup` in user code like the below.
@nayato Should it be apply directly to `XThread`, like it does in `AbstractSocketByteChannel` and `SocketDatagramChannel`? But one problem is the api is only available for netfx and netstandard2.0, so not available for all netcoreapp1.x, and 2.x before directly support for `netstandard2.0` is added.
```cs
void CreateLongRunningTask(XParameterizedThreadStart threadStartFunc)
{
#if NETSTANDARD1_3
CreateLongRunningTaskUnsafe(threadStartFunc);
#else//NET45 || NETSTANDARD2_0
if (ExecutionContext.IsFlowSuppressed())
{
CreateLongRunningTaskUnsafe(threadStartFunc);
}
else
{
using (ExecutionContext.SuppressFlow())
{
CreateLongRunningTaskUnsafe(threadStartFunc);
}
}
#endif
}
```

Test code: an edited version of `Echo.Server`.
```cs

static async Task RunServerAsync()
{
IEventLoopGroup bossGroup;
IEventLoopGroup workerGroup;

#if NET451
System.Runtime.Remoting.Messaging.CallContext.LogicalSetData("test001", new { B = 1 });
#else//netcoreapp1.1
var local = new System.Threading.AsyncLocal();
local.Value = new { C = 1 };
#endif
if (ServerSettings.UseLibuv)
{
var dispatcher = new DispatcherEventLoopGroup();
bossGroup = dispatcher;
workerGroup = new WorkerEventLoopGroup(dispatcher);
}
else
{
bossGroup = new MultithreadEventLoopGroup(1);
workerGroup = new MultithreadEventLoopGroup();
}

#if NET451
System.Runtime.Remoting.Messaging.CallContext.FreeNamedDataSlot("test001");
Console.WriteLine("LogicalData(out dotnetty): " + System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("test001"));
#else//netcoreapp1.1
local.Value = null;
Console.WriteLine("AsyncLocal(out dotnetty): " + local.Value);
#endif
bossGroup.GetNext().Execute(() =>
{
#if NET451
Console.WriteLine("LogicalData(in dotnetty's boss): " + System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("test001"));
#else//netcoreapp1.1
Console.WriteLine("AsyncLocal(in dotnetty's boss): " + local.Value);
#endif
});
workerGroup.GetNext().Execute(() =>
{
#if NET451
Console.WriteLine("LogicalData(in dotnetty's worker): " + System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("test001"));
#else//netcoreapp1.1
Console.WriteLine("AsyncLocal(in dotnetty's worker): " + local.Value);
#endif
});
Console.ReadLine();
}

static void Main() => RunServerAsync().Wait();
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.