1
1
import { defineIntegration , getCurrentScope } from '@sentry/core' ;
2
- import type { Contexts , Event , EventHint , IntegrationFn } from '@sentry/types' ;
2
+ import type { Contexts , Event , EventHint , IntegrationFn , IntegrationFnResult } from '@sentry/types' ;
3
3
import { logger } from '@sentry/utils' ;
4
4
import * as inspector from 'inspector' ;
5
5
import { Worker } from 'worker_threads' ;
@@ -32,33 +32,69 @@ async function getContexts(client: NodeClient): Promise<Contexts> {
32
32
33
33
const INTEGRATION_NAME = 'Anr' ;
34
34
35
+ type AnrInternal = { startWorker : ( ) => void ; stopWorker : ( ) => void } ;
36
+
35
37
const _anrIntegration = ( ( options : Partial < AnrIntegrationOptions > = { } ) => {
38
+ let worker : Promise < ( ) => void > | undefined ;
39
+ let client : NodeClient | undefined ;
40
+
36
41
return {
37
42
name : INTEGRATION_NAME ,
38
- setup ( client : NodeClient ) {
43
+ startWorker : ( ) => {
44
+ if ( worker ) {
45
+ return ;
46
+ }
47
+
48
+ if ( client ) {
49
+ worker = _startWorker ( client , options ) ;
50
+ }
51
+ } ,
52
+ stopWorker : ( ) => {
53
+ if ( worker ) {
54
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
55
+ worker . then ( stop => {
56
+ stop ( ) ;
57
+ worker = undefined ;
58
+ } ) ;
59
+ }
60
+ } ,
61
+ setup ( initClient : NodeClient ) {
39
62
if ( NODE_VERSION . major < 16 || ( NODE_VERSION . major === 16 && NODE_VERSION . minor < 17 ) ) {
40
63
throw new Error ( 'ANR detection requires Node 16.17.0 or later' ) ;
41
64
}
42
65
43
- // setImmediate is used to ensure that all other integrations have been setup
44
- setImmediate ( ( ) => _startWorker ( client , options ) ) ;
66
+ client = initClient ;
67
+
68
+ // setImmediate is used to ensure that all other integrations have had their setup called first.
69
+ // This allows us to call into all integrations to fetch the full context
70
+ setImmediate ( ( ) => this . startWorker ( ) ) ;
45
71
} ,
46
- } ;
72
+ } as IntegrationFnResult & AnrInternal ;
47
73
} ) satisfies IntegrationFn ;
48
74
49
- export const anrIntegration = defineIntegration ( _anrIntegration ) ;
75
+ type AnrReturn = ( options ?: Partial < AnrIntegrationOptions > ) => IntegrationFnResult & AnrInternal ;
76
+
77
+ export const anrIntegration = defineIntegration ( _anrIntegration ) as AnrReturn ;
50
78
51
79
/**
52
80
* Starts the ANR worker thread
81
+ *
82
+ * @returns A function to stop the worker
53
83
*/
54
- async function _startWorker ( client : NodeClient , _options : Partial < AnrIntegrationOptions > ) : Promise < void > {
55
- const contexts = await getContexts ( client ) ;
84
+ async function _startWorker (
85
+ client : NodeClient ,
86
+ integrationOptions : Partial < AnrIntegrationOptions > ,
87
+ ) : Promise < ( ) => void > {
56
88
const dsn = client . getDsn ( ) ;
57
89
58
90
if ( ! dsn ) {
59
- return ;
91
+ return ( ) => {
92
+ //
93
+ } ;
60
94
}
61
95
96
+ const contexts = await getContexts ( client ) ;
97
+
62
98
// These will not be accurate if sent later from the worker thread
63
99
delete contexts . app ?. app_memory ;
64
100
delete contexts . device ?. free_memory ;
@@ -78,11 +114,11 @@ async function _startWorker(client: NodeClient, _options: Partial<AnrIntegration
78
114
release : initOptions . release ,
79
115
dist : initOptions . dist ,
80
116
sdkMetadata,
81
- appRootPath : _options . appRootPath ,
82
- pollInterval : _options . pollInterval || DEFAULT_INTERVAL ,
83
- anrThreshold : _options . anrThreshold || DEFAULT_HANG_THRESHOLD ,
84
- captureStackTrace : ! ! _options . captureStackTrace ,
85
- staticTags : _options . staticTags || { } ,
117
+ appRootPath : integrationOptions . appRootPath ,
118
+ pollInterval : integrationOptions . pollInterval || DEFAULT_INTERVAL ,
119
+ anrThreshold : integrationOptions . anrThreshold || DEFAULT_HANG_THRESHOLD ,
120
+ captureStackTrace : ! ! integrationOptions . captureStackTrace ,
121
+ staticTags : integrationOptions . staticTags || { } ,
86
122
contexts,
87
123
} ;
88
124
@@ -135,4 +171,9 @@ async function _startWorker(client: NodeClient, _options: Partial<AnrIntegration
135
171
136
172
// Ensure this thread can't block app exit
137
173
worker . unref ( ) ;
174
+
175
+ return ( ) => {
176
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
177
+ worker . terminate ( ) ;
178
+ } ;
138
179
}
0 commit comments