Skip to content

fix(replay): Keep pending video when stop follows flush - #9429

Merged
romtsn merged 6 commits into
mainfrom
fix/replay-flush-stop-pending-video
Oct 28, 2026
Merged

romtsn merged 6 commits into
mainfrom
fix/replay-flush-stop-pending-video

Conversation

@romtsn

@romtsn romtsn commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

📜 Description

The video encoding completion in SentrySessionReplay.createAndCaptureInBackground captured the replay with [weak self]. SentrySDK.replay.stop() releases the replay, so when stop() comes right after flush(), encoding finishes after the replay is gone and the segment is dropped. No replay envelope is sent, in buffer or session mode.

This PR captures the replay strongly in the completion. The video maker releases the closure after it runs, so the replay lives only until the pending encoding finishes. In session mode, the pause segment that stop() creates is now sent as well.

Because a segment can now arrive after stop(), a start() in that window would let the old replay's late segment overwrite the new replay's global crash-sync info (segment id and last segment end). The same late segment, if rate limited, would also stop the new replay, which may be buffering and would otherwise outlive the rate limit. The integration now applies both the crash-sync update and the rate-limit stop only to segments of the current replay. A late segment still clears the shared touch tracker's finished touches; that needs a touch tracker per replay and is left as is.

This is the Cocoa side of the Android fix in getsentry/sentry-java#6340. The other two Android problems do not apply here:

  • Cocoa names video files by frame timestamp, so a new video cannot overwrite a flushed one.
  • Cocoa assigns segment ids when encoding completes, under a lock on a serial queue, so ids are not reused.

💡 Motivation and Context

Fixes #9320
Fixes COCOA-2050

💚 How did you test it?

  • New testFlush_whenReleasedBeforeVideoCreationCompletes_shouldStillSendSegment: flush, pause, release the replay, then finish encoding. It fails without the fix and passes with it.
  • testDealloc_DoesNotRetainSessionReplayDuringVideoCreation is now testDealloc_RetainsSessionReplayOnlyUntilVideoCreationCompletes. It checks that the replay is released after encoding finishes.
  • New testSessionReplayNewSegment_whenSegmentOfStoppedReplay_shouldNotOverwriteCrashInfo: stop, start, then send a segment for the old and the new replay id. It fails without the guard.
  • New testSessionReplayNewSegment_whenRateLimitedSegmentOfStoppedReplay_shouldNotStopCurrentReplay: a rate-limited segment of the stopped replay leaves the current one running, one of the current replay stops it. It fails without the guard. The existing rate-limit tests now send segments for the current replay instead of a random id.
  • SentrySessionReplayIntegrationTests (94 tests) and SentrySessionReplayTests (76 tests) pass on the iOS 18.6 simulator. make format and make analyze are clean.

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.
  • If I added a new public API, I also added it to the SentryObjC wrapper.

@linear-code

linear-code Bot commented Oct 23, 2026

Copy link
Copy Markdown

COCOA-2050

The video encoding completion captured the session replay weakly.
SentrySDK.replay.stop() releases the replay, so a stop right after
flush() dropped the encoded segment and no replay was sent.

Capture the replay strongly in the completion. The closure is
released after it runs, so the replay lives only until the pending
encoding finishes.

Fixes #9320
Fixes COCOA-2050
@romtsn
romtsn force-pushed the fix/replay-flush-stop-pending-video branch from 10eaa1e to 7b36d78 Compare October 23, 2026 09:41
The encoding completion now holds the replay until it finishes, so a
segment can arrive after stop(). If start() already made a new
replay, that segment overwrote the new replay's global crash-sync
segment id and end time.

Update the crash-sync info only for segments of the replay it was
last started for.
@romtsn romtsn added the run-full-ci Allows gated GitHub Action workflows to run for a labelled pull request label Oct 23, 2026
@sentry

sentry Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Size Analysis

1 component analyzed

iOS Builds

Name Configuration Version Download Size Install Size
SDK-Size (iOS)
io.sentry.sample.SDK-Size
Release 9.31.0 (1) 1.2 MB (+582 B) 3.1 MB (+16.4 KB)

Configure sentry-cocoa status check rules

@sentry

sentry Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
SDK-Size io.sentry.sample.SDK-Size 9.31.0 (1) Release

⚙️ sentry-cocoa Build Distribution Settings

@itaybre itaybre left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Almost LGTM, some comments to check

A pending encoding can now release the replay on the processing
queue. Hold the root view weakly, so the replay never deallocates a
UIView off the main thread. The app owns the window.

Reset and update the crash-sync info under the replay id lock, so a
late segment check can't interleave with a new replay's reset.
@romtsn

romtsn commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

@itaybre great comments, thanks for catching those! addressed all in 8f10a97

@romtsn
romtsn enabled auto-merge (squash) October 27, 2026 12:48

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d89e7bc. Configure here.

A rate-limited segment stops the current replay. A late segment of a
stopped replay could now reach that path and stop the replay that
replaced it, which may be buffering and would outlive the rate limit.

Apply the current-replay-id guard to the rate-limit branch as well,
and rename the id to currentReplayId since it now serves both checks.
Existing rate-limit tests send segments for the current replay.
@romtsn
romtsn requested a review from a team as a code owner October 27, 2026 21:13
@romtsn
romtsn merged commit 936260e into main Oct 28, 2026
284 of 286 checks passed
@romtsn
romtsn deleted the fix/replay-flush-stop-pending-video branch October 28, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved run-full-ci Allows gated GitHub Action workflows to run for a labelled pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replay flush followed by immediate stop drops pending video

2 participants