Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Ensure all buffered logs are sent to Sentry when the application terminates unexpectedly ([#4425](https://github.com/getsentry/sentry-dotnet/pull/4425))
- `InvalidOperationException` potentially thrown during a race condition, especially in concurrent high-volume logging scenarios ([#4428](https://github.com/getsentry/sentry-dotnet/pull/4428))
- Blocking calls are no longer treated as unhandled crashes ([#4458](https://github.com/getsentry/sentry-dotnet/pull/4458))
- The SDK avoids redundant scope sync after transaction finish ([#4479](https://github.com/getsentry/sentry-dotnet/pull/4479))

### Dependencies

Expand Down
5 changes: 0 additions & 5 deletions src/Sentry/Scope.cs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice - thanks @bitsandfoxes !

My only question is about how we want to approach the fix. What you've done will work... it does depend on us always doing this:

            scope.ResetTransaction(transactionTracer);
            scope.SetPropagationContext(new SentryPropagationContext());

What's more, if there's a race and this line returns false:

if (ReferenceEquals(_transaction.Value, expectedCurrentTransaction))

Then we could end up running this multiple times:

scope.SetPropagationContext(new SentryPropagationContext());

Alternative solution

We could possibly rewrite ResetTransaction to do this:

            if (ReferenceEquals(_transaction.Value, expectedCurrentTransaction))
            {
                _transaction.Value = null;
                SetPropagationContext(new SentryPropagationContext());
            }

So both the scope sync and the resetting of the propagation context always happen if you call RestTransaction (but only once, since it's in a lock that will prevent races).

Original file line number Diff line number Diff line change
Expand Up @@ -818,11 +818,6 @@ internal void ResetTransaction(ITransactionTracer? expectedCurrentTransaction)
if (ReferenceEquals(_transaction.Value, expectedCurrentTransaction))
{
_transaction.Value = null;
if (Options.EnableScopeSync)
{
// We have to restore the trace on the native layers to be in sync with the current scope
Options.ScopeObserver?.SetTrace(PropagationContext.TraceId, PropagationContext.SpanId);
}
}
}
finally
Expand Down
28 changes: 0 additions & 28 deletions test/Sentry.Tests/ScopeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,34 +342,6 @@ public void Transaction_SetToNull_ObserverSetsTraceFromPropagationContextIfEnabl
observer.Received(expectedCount).SetTrace(Arg.Is(expectedTraceId), Arg.Is(expectedSpanId));
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void ResetTransaction_MatchingTransaction_ObserverSetsTraceFromPropagationContextIfEnabled(bool enableScopeSync)
{
// Arrange
var observer = Substitute.For<IScopeObserver>();
var scope = new Scope(new SentryOptions
{
ScopeObserver = observer,
EnableScopeSync = enableScopeSync
});
var transaction = new TransactionTracer(DisabledHub.Instance, "test-transaction", "op");
scope.Transaction = transaction;

var expectedTraceId = scope.PropagationContext.TraceId;
var expectedSpanId = scope.PropagationContext.SpanId;
var expectedCount = enableScopeSync ? 1 : 0;

observer.ClearReceivedCalls();

// Act
scope.ResetTransaction(transaction);

// Assert
observer.Received(expectedCount).SetTrace(Arg.Is(expectedTraceId), Arg.Is(expectedSpanId));
}

[Theory]
[InlineData(true)]
[InlineData(false)]
Expand Down
Loading