newrelic-dotnet-agent
newrelic-dotnet-agent copied to clipboard
Include a method run via `Task.Run()` in a distributed trace
Is your feature request related to a problem? Please describe.
Apologies if I mess up the NR terminology. Here is the problem I have.
I have a background worker I'm trying to instrument via distributed tracing. Everything works great except for the part where my worker does a bulk of work in a task that is not awaited.
Specifically a method that looks something like this
[Trace]
public void StartJobWithoutWaiting(...)
{
Task.Run(async()=>{
...
// do work
})
}
StartJobWithoutWaiting() does show up in the distributed trace, but it's duration does not represent the work happening in the Task.Run(). It also does not include any of the other work happening in the task.
I understand that async void methods are not supported
https://docs.newrelic.com/docs/apm/agents/net-agent/other-features/async-support-net/#task-not-void
I'm trying to find a way to somehow represent the time with the trace for StartJobWithoutWaiting().
The work inside the Task.Run() also includes datastore operations, so ideally, I would like to be able to trace all those operations as well.
Or perhaps generate a custom span programatically via manual instrumentation of the Task, possibly using ContinueWith(). But I could not find anything in the NR .NET API that lets you do this.
There are methods like these, but they only work in the context of an existing transaction.
Feature Description
I need a way to trace code run using a non-awaited Task.Run() for distributed tracing.
Not just duration, but also trace the API and datastore ops, similar to what I get with automated instrumentation.
Describe Alternatives
If automatic instrumentation won't work, it is possible to add manual instrumentation that will show up with distributed tracing.
Additional context
Add any other context here.
Priority
Please help us better understand this feature request by choosing a priority from the following options: [Really Want]
Hello @bdurrani,
Thanks for the feature request! As you found, the customer facing agent API does not currently provide any automatic functionality, or manual method, to link un-awaited async work to the code that called it. There are some internal instrumentation wrappers that provide something close to this, that could potentially be exposed for customer use though.
I have assigned this Feature Request to @elucus for potential inclusion in a future feature pack.
In the meantime I do think there are some things you can try that may get you closer to seeing all the data you want (albeit not grouped like you are asking for). If you extract a method for the work you are doing without waiting, decorate it with the [Transaction] attribute, and pass that to Task.Run() then you should get visibility in to how long this currently untracked work is taking, as well as visibility in to the external and database calls.
While it's not ideal, you could also record some custom transaction attributes to help correlate these related pieces of work.
Pseudo Code Example:
[Trace]
public void StartJobWithoutWaiting(...)
{
var guid = Guid.NewGuid();
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("ManualCorrelationGuid", guid);
Task.Run(TrackPreviouslyUntrackedWork(guid, ...));
}
[Transaction]
public async void TrackPreviouslyUntrackedWork(Guid guid, ...)
{
NewRelic.Api.Agent.NewRelic.GetAgent().CurrentTransaction.AddCustomAttribute("ManualCorrelationGuid", guid);
// Database calls...
// External calls...
...
}
Thanks @JcolemanNR . I will try this out
https://issues.newrelic.com/browse/NEWRELIC-3665
Work has been completed on this issue.