Skip to content

Conversation

@bitsandfoxes
Copy link
Contributor

@bitsandfoxes bitsandfoxes commented Oct 17, 2025

Resolves #4632
Followup on #4633

Problem

Sessions that end in Unhandled can later on still crash. Updating a session with an end status is a terminal operation, see getsentry/sentry-docs#15086 and once updated, sessions must not receive further updates. We need to make sure the SDK finishes a session only when it is confident, that a session is actually finished.

Proposal

Instead of updating (and ending) a session with SessionEndStatus.Unhandled right away we persist the state to disk. We can make use of the fact that there is a separation between PersistedSessionUpdate and SessionUpdate.

  • PersistedSessionUpdate is used locally only, the SDK does not send this to Sentry and we can add a flag PendingUnhandled to it
  • SessionUpdate is the actual update the SDK sends to Sentry

The flow is as follows:

  1. Unhandled non-terminal exception captured (i.e. via Unity loghandling)
  2. The client triggers the session to be marked as Unhandled and the update is persisted to disk
  3. If the app crashes we end the session as Crashed, overwriting the pending unhandled state
  4. If the app exits normally, we check for the endstatus and overwrite Exited with Unhandled.

TODO

Currently, the SDK relies on restarts of the application to send the SessionEndStatus. Ideally, we would also hook into some shutdown mechanism, or at the very least, closing the SDK should also end any active sessions.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against a7ff327

@bitsandfoxes bitsandfoxes marked this pull request as ready for review October 20, 2025 19:51
cursor[bot]

This comment was marked as outdated.

@codecov
Copy link

codecov bot commented Oct 20, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.20%. Comparing base (624524f) to head (a7ff327).

Additional details and impacted files
@@                       Coverage Diff                       @@
##           feat/session-type-unhandled    #4653      +/-   ##
===============================================================
+ Coverage                        73.17%   73.20%   +0.03%     
===============================================================
  Files                              479      479              
  Lines                            17349    17370      +21     
  Branches                          3426     3431       +5     
===============================================================
+ Hits                             12695    12716      +21     
  Misses                            3804     3804              
  Partials                           850      850              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Session State Loss During Persistence

The PauseSession method calls PersistSession without passing the pendingUnhandled state. This causes sessions marked as pending unhandled to lose this status when persisted, leading to them being incorrectly recovered as Exited instead of Unhandled on app restart.

src/Sentry/GlobalSessionManager.cs#L43-L44

// potential race conditions.
private void PersistSession(SessionUpdate update, DateTimeOffset? pauseTimestamp = null, bool pendingUnhandled = false)

src/Sentry/GlobalSessionManager.cs#L290-L305

public void PauseSession()
{
if (_currentSession is not { } session)
{
_options.LogWarning("Attempted to pause a session, but a session has not been started.");
return;
}
_options.LogInfo("Pausing session (SID: {0}; DID: {1}).", session.Id, session.DistinctId);
var now = _clock.GetUtcNow();
_lastPauseTimestamp = now;
PersistSession(session.CreateUpdate(false, now), now);
}
public IReadOnlyList<SessionUpdate> ResumeSession()

Fix in Cursor Fix in Web


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant