Avoid capture AsyncLocal<T>/CallContext.LogicalData to DotNetty's XThread?
- 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
Assessment
This issue has not been assessed yet.