I have the following code:
Task task = null;
var channel = System.Threading.Channels.Channel.CreateUnbounded<string>();
using (var activity = MyActivitySource.StartActivity("Parent"))
{
task = Task.Factory.StartNew(async () =>
{
//Activity.Current = null;
var item = await channel.Reader.ReadAsync();
Console.WriteLine("Task: {0}", Activity.Current?.DisplayName);
});
}
Console.WriteLine("Current end: {0}", Activity.Current?.DisplayName ?? "(null)");
await channel.Writer.WriteAsync("something");
await task;
I would like to start the task without injecting Activity. I cannot create the task outside the using(var acrivity...).
One option (I suppose) is setting Activity.Current = null at the beginning of the task. Is there an alternative option?
My preferred solution would be to move the "processing" code into a separate top-level loop. I.e., move the code currently within
StartNew
into a completely separate method, wrap it in anawait foreach (var item in channel.Reader.ReadAllAsync())
, and start that loop at the time you start your channel. Thus essentially making it anActionBlock
of sorts.You may need to augment your current
string
item with other values to make that work. I.e., if you need per-item completion, then you can replacestring
with(string Item, TaskCompletionSource Completion)
.There is another solution that may work (but I really recommend using the top-level loop instead): you can suppress the logical context flow (which suppresses all
AsyncLocal
-style values). But then I would recommend ensuring the task has started on the thread pool thread before letting it escape that block, just in case some code waits synchronously. So that would look like this:But really, I think putting in a "main loop" would be better.