Skip to content

Commit 8f9b963

Browse files
authored
fix(span): Skip idle span creation when app is in the background (#4995)
* fix: Skip idle span creation when app is in background * Add changelog
1 parent 13d9dc0 commit 8f9b963

File tree

4 files changed

+56
-0
lines changed

4 files changed

+56
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
99
## Unreleased
1010

11+
### Fixes
12+
13+
- Skip idle span creation when app is in background ([#4995](https://github.com/getsentry/sentry-react-native/pull/4995))
14+
1115
### Dependencies
1216

1317
- Bump JavaScript SDK from v8.54.0 to v8.55.0 ([#4981](https://github.com/getsentry/sentry-react-native/pull/4981))

packages/core/src/js/tracing/span.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
spanToJSON,
1313
startIdleSpan as coreStartIdleSpan,
1414
} from '@sentry/core';
15+
import { AppState } from 'react-native';
1516

1617
import { isRootSpan } from '../utils/span';
1718
import { adjustTransactionDuration, cancelInBackground } from './onSpanEndUtils';
@@ -104,6 +105,12 @@ export const startIdleSpan = (
104105
return new SentryNonRecordingSpan();
105106
}
106107

108+
const currentAppState = AppState.currentState;
109+
if (currentAppState === 'background') {
110+
logger.debug(`[startIdleSpan] App is already in background, not starting span for ${startSpanOption.name}`);
111+
return new SentryNonRecordingSpan();
112+
}
113+
107114
getCurrentScope().setPropagationContext(generatePropagationContext());
108115

109116
const span = coreStartIdleSpan(startSpanOption, { finalTimeout, idleTimeout });

packages/core/test/tracing/idleNavigationSpan.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe('startIdleNavigationSpan', () => {
3535
jest.useFakeTimers();
3636
NATIVE.enableNative = true;
3737
mockedAppState.isAvailable = true;
38+
mockedAppState.currentState = 'active';
3839
mockedAppState.addEventListener = (_, listener) => {
3940
mockedAppState.listener = listener;
4041
return {
@@ -82,6 +83,37 @@ describe('startIdleNavigationSpan', () => {
8283
expect(spanToJSON(transaction!).timestamp).toBeDefined();
8384
});
8485

86+
it('Returns non-recording span when app is already in background', () => {
87+
mockedAppState.currentState = 'background';
88+
89+
const span = startIdleNavigationSpan({
90+
name: 'test',
91+
});
92+
93+
// Non-recording spans don't become active
94+
expect(getActiveSpan()).toBeUndefined();
95+
96+
// Verify it's a non-recording span
97+
expect(span).toBeDefined();
98+
expect(span.constructor.name).toBe('SentryNonRecordingSpan');
99+
100+
// No AppState listener should be set up for non-recording spans
101+
expect(mockedAppState.removeSubscription).not.toHaveBeenCalled();
102+
});
103+
104+
it('Does not set up AppState listener for background spans', () => {
105+
mockedAppState.currentState = 'background';
106+
107+
startIdleNavigationSpan({
108+
name: 'test',
109+
});
110+
111+
mockedAppState.setState('active');
112+
113+
// No subscription removal should happen since no listener was set up
114+
expect(mockedAppState.removeSubscription).not.toHaveBeenCalled();
115+
});
116+
85117
describe('Start a new active root span (without parent)', () => {
86118
it('Starts a new span when there is no active span', () => {
87119
const span = startIdleNavigationSpan({

packages/core/test/tracing/integrations/userInteraction.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ describe('User Interaction Tracing', () => {
6666
jest.useFakeTimers();
6767
NATIVE.enableNative = true;
6868
mockedAppState.isAvailable = true;
69+
mockedAppState.currentState = 'active';
6970
mockedAppState.addEventListener = (_, listener) => {
7071
mockedAppState.listener = listener;
7172
return {
@@ -291,5 +292,17 @@ describe('User Interaction Tracing', () => {
291292
);
292293
expect(interactionTransactionContext!.timestamp).toBeLessThanOrEqual(routingTransactionContext!.start_timestamp!);
293294
});
295+
296+
test('does not start UI span when app is in background', () => {
297+
mockedAppState.currentState = 'background';
298+
299+
startUserInteractionSpan(mockedUserInteractionId);
300+
301+
// No active span should be created
302+
expect(getActiveSpan()).toBeUndefined();
303+
304+
// No events should be queued
305+
expect(client.eventQueue).toHaveLength(0);
306+
});
294307
});
295308
});

0 commit comments

Comments
 (0)