getsentry / getsentry/sentry-react-native

Session Replay resumes capture on didBecomeActive with no delay, causing fatal iOS App Hangs (watchdog kill)

クローズ
#6,701 コメント 2 件 リアクション 0 件 担当者 1 名 @alwx が担当を希望しています GitHub で見る
Bug React-Native Replays
主要言語
TypeScript
スター
1.8k
フォーク
366
平均マージ
1日 5時間
マージ済み PR(30日)
93

説明

### What React Native libraries do you use?

React Native without Frameworks

### Are you using sentry.io or on-premise?

sentry.io (SaS)

### Are you using any other error monitoring solution alongside Sentry?

No

### Other Error Monitoring Solution Name

_No response_

### @sentry/react-native SDK Version

8.8.0

### How does your development environment look like?

````
⬇ Place the `npx react-native@latest info` output here. ⬇
System:
OS: macOS 26.5.1
CPU: (10) arm64 Apple M5
Memory: 253.89 MB / 24.00 GB
Binaries:
Node: 26.0.0
Yarn: 1.22.22
npm: 11.18.0
Watchman: Not Found
IDEs:
Xcode: 26.6/17F113
Languages:
Java: 21.0.11
Ruby: 3.3.6
npmPackages:
"@react-native-community/cli": 20.1.2
react: 19.1.0
react-native: 0.81.1
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true

````

### Sentry.init()

````js
Sentry.init({
dsn: sentryDsn,
enabled: true,
environment: __DEV__ ? 'development' : 'production',
sendDefaultPii: false,
tracesSampleRate: 0.2,
profilesSampleRate: 0.1,
enableLogs: true,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
integrations: [
navigationIntegration,
Sentry.mobileReplayIntegration({
maskAllText: false,
maskAllImages: false,
maskAllVectors: false,
// Skip video / AVKit view trees during Session Replay screenshotting.
// Traversing RCTVideo (and AVPlayer fullscreen presentation layers) can
// fatal with -[NSConcreteValue doubleValue] while CA animations run.
// See: getsentry/sentry-react-native#5548, getsentry/sentry-cocoa#7810
excludedViewClasses: [
'RCTVideo',
'AVPlayer',
'AVPlayback',
'AVNowPlaying',
'AVFullScreen',
'AVKit',
],
}),
],
````

### Steps to Reproduce

# Session Replay resumes capture on didBecomeActive with no delay, causing fatal iOS App Hangs (watchdog kill)

## Description

On iOS, Session Replay's screenshot pass is resumed synchronously on
`UIApplication.didBecomeActiveNotification`. Because the capture walks the view
hierarchy and re-renders the window on the main thread, and because iOS applies
its strictest watchdog to foreground transitions, a heavy view tree at resume
can block the main thread past 2s and the app is terminated.

We are seeing this in production as `Fatal App Hang Fully Blocked`, with
`SentrySessionReplay.takeScreenshot` as the symbolicated culprit.

The relevant code is `SentrySessionReplayIntegration.swift`, which wires resume
straight to the notification:

```swift
notificationCenter.addObserver(self, selector: #selector(pause),
name: UIApplication.didEnterBackgroundNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(resume),
name: UIApplication.didBecomeActiveNotification, object: nil)
```

There is no configurable delay or jitter before the first capture after resume,
and no way to defer it from JS: `SentryReplayApi` exposes `pause`/`resume`/
`start`/`stop` natively, but the React Native bridge only forwards
`captureReplay` and `getCurrentReplayId` (`NativeRNSentry.d.ts`), so a React
Native app cannot pause replay across the foreground transition even as a
workaround.

## Evidence

Two events from the same issue, on very different hardware, both with the
identical breadcrumb shape:

**iPhone XR, iOS 18.1.1**
```
10:17:20.609 app.lifecycle background
10:17:21.412 device.event Low memory LOW_MEMORY
... 2h 56m ...
13:13:52.441 app.lifecycle foreground
13:13:52.593 app.lifecycle active
13:13:53-54 app's own rehydration requests
13:13:55.628 Fatal App Hang Fully Blocked <- 3.2s after active
```

**iPhone 16 Pro, iOS 26.6.1**
```
04:40:37.783 app.lifecycle background
... ~4 min ...
04:44:34.536 app.lifecycle foreground
04:44:34.766 app.lifecycle active
04:44:34-35 app's own rehydration requests
04:44:36.970 Fatal App Hang Fully Blocked <- 2.4s after active
```

Points worth noting:

- Time spent in background is irrelevant (2h56m vs 4min); the trigger is the
resume itself.
- It reproduces on current hardware, not just older devices — an iPhone 16 Pro
on iOS 26 hit the same group as an iPhone XR on iOS 18.
- The JS thread is idle in both. This is entirely native.
- `enableViewRendererV2` is on (SDK default), so this is with the fast renderer
already in use.

## Steps to reproduce

1. Init with Session Replay in buffer mode (`replaysOnErrorSampleRate: 1.0`).
2. Open a screen with a large view tree (in our case a chat list backed by a
long message list).
3. Background the app.
4. Return to the foreground while the app also does meaningful work on the main
thread at resume (state rehydration, list re-render).
5. On a device under memory pressure this blocks past the watchdog threshold
and iOS terminates the app.

Reproduction is probabilistic rather than deterministic — it depends on how
much work lands in the same window. We have 4 events across 4 users.

## Expected result

Resuming replay after a foreground transition should not be able to terminate
the app. Some possibilities, in rough order of preference:

1. Defer the first capture after `didBecomeActive` by a short interval, or
schedule it off the watchdog-critical window.
2. Expose an option for that delay in `SentryReplayOptions` /
`MobileReplayOptions`.
3. Bridge `SentryReplayApi`'s `pause`/`resume` to React Native, so apps can at
least implement the workaround themselves.

## Actual result

The first capture runs immediately on `didBecomeActive`, on the main thread,
and the watchdog kills the app.

### Expected Result

No App hang

### Actual Result

App hangs after it comes to foreground state

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。