Open mattjohnsonpint opened 1 year ago
Also, explain clearly that global mode should be false
for background workers. Update docs for IsGlobalMode.
POC:
public class Worker : BackgroundService
{
private readonly IHub _hub;
public Worker(IHub hub)
{
_hub = hub;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using var _ = _hub.PushScope();
var transaction = _hub.StartTransaction($"{nameof(Worker)}.{nameof(DoWorkAsync)}", "function");
try
{
_hub.ConfigureScope(scope =>
{
scope.Clear();
scope.Transaction = transaction;
});
await DoWorkAsync(stoppingToken);
}
catch(Exception exception)
{
transaction.Finish(exception);
}
finally
{
transaction.Finish();
}
}
}
}
Updated POC. Requires vNext (3.31.0) for #2303 & #2309.
public class Worker : BackgroundService
{
private readonly IHub _hub;
public Worker(IHub hub)
{
_hub = hub;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _hub.WithScopeAsync(async scope =>
{
scope.Clear();
var transaction = _hub.StartTransaction($"{nameof(Worker)}.{nameof(DoWorkAsync)}", "function");
scope.Transaction = transaction;
try
{
await DoWorkAsync(stoppingToken);
}
catch (Exception exception)
{
transaction.Finish(exception);
}
finally
{
transaction.Finish();
}
});
}
}
}
@mattjohnsonpint Just a quick follow up question, how would I retrieve a transaction like the one started in your sample? With SentrySdk.GetSpan()
?
ISpan? span = SentrySdk.GetSpan();
if (span is ITransaction transaction)
{
transaction.StartChild("Something");
}
@bruno-garcia
@mattjohnsonpint Just a quick follow up question, how would I retrieve a transaction like the one started in your sample? With
SentrySdk.GetSpan()
?ISpan? span = SentrySdk.GetSpan(); if (span is ITransaction transaction) { transaction.StartChild("Something"); }
@Kampfmoehre could you give a bit more context? Are you trying to get the currently active transaction or a specific transaction (one that you've seen at some point earlier in your code)?
@jamescrosswell I have a worker service that is calling a method which is also used by others. I don't want to pass the transaction directly to it, since all other callers then also would need to provide one and it would make unit tests more complex.
The transaction is either the one I have manually started in the worker loop (or from another worker that also calls this method) or it could be one that was set by Sentry itself from a HTTP request somewhere else in the code.
Let's just say the DoWorkAsync
method wants to provide some spans to a transaction if one exists.
Should it look like this or are there better ways to achieve this?
public async Task DoWorkAsync(CancellationToken cancellationToken)
{
ISpan? span = SentrySdk.GetSpan();
ISpan? loadDataSpan = span?.StarChild("load-data");
var someData = await repo.LoadSomethingAsync();
loadDataSpan?.Finish(SpanStatus.Ok);
ISpan? processDataSpan = span?.StartChild("process-data");
await repo.ProcessData(someData);
processDataSpan?.Finish(SpanStatus.Ok);
// ...
}
Should it look like this or are there better ways to achieve this?
That looks fine in that case. Just be aware that when Sentry isn't initialised (e.g. when the code is run by unit tests) that SentrySdk.GetSpan()
will return null
since the underlying implementation being called in that instance is the DisabledHub.
Also, much more importantly, none of the code in calls like this will get executed (for the same reason):
SentrySdk.ConfigureScope(scope => {
// Any code you write here only gets executed when Sentry is initiailised
});
@mattjohnsonpint scope.Clear and .WithScope don't exist anymore, so the samples above no longer work.
I was looking at this issue for means to introduce IsGlobalScopeEnabled = false on MAUI mobile client since my app has multiple transactions happening at once and spans get recorded to the wrong transaction.
@MichaelLHerman - I don't work for Sentry (or on this project) any more, but I'm sure @jamescrosswell will be happy to help you.
Hi @MichaelLHerman,
scope.Clear and .WithScope don't exist anymore, so the samples above no longer work.
Generally you can replace WithScope with overloads of the Capture* methods accepting a scope callback. In the case of the POC above, I see CaptureTransaction isn't called explicitly so Matt's first/original POC would be more appropriate.
I was looking at this issue for means to introduce IsGlobalScopeEnabled = false on MAUI mobile client since my app has multiple transactions happening at once and spans get recorded to the wrong transaction.
I see you opened a new issue for this - thank you for doing that and for the extra context! I'll reply there:
Problem Statement
We should provide documentation and samples for integrating Sentry with .NET Worker Services.
Note, we already have the Generic Host sample, but this is slightly different.
Solution Brainstorm
dotnet new worker
Sentry.Extensions.Logging