11import { 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' ;
33import { logger } from '@sentry/utils' ;
44import * as inspector from 'inspector' ;
55import { Worker } from 'worker_threads' ;
@@ -32,33 +32,69 @@ async function getContexts(client: NodeClient): Promise<Contexts> {
3232
3333const INTEGRATION_NAME = 'Anr' ;
3434
35+ type AnrInternal = { startWorker : ( ) => void ; stopWorker : ( ) => void } ;
36+
3537const _anrIntegration = ( ( options : Partial < AnrIntegrationOptions > = { } ) => {
38+ let worker : Promise < ( ) => void > | undefined ;
39+ let client : NodeClient | undefined ;
40+
3641 return {
3742 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 ) {
3962 if ( NODE_VERSION . major < 16 || ( NODE_VERSION . major === 16 && NODE_VERSION . minor < 17 ) ) {
4063 throw new Error ( 'ANR detection requires Node 16.17.0 or later' ) ;
4164 }
4265
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 ( ) ) ;
4571 } ,
46- } ;
72+ } as IntegrationFnResult & AnrInternal ;
4773} ) satisfies IntegrationFn ;
4874
49- export const anrIntegration = defineIntegration ( _anrIntegration ) ;
75+ type AnrReturn = ( options ?: Partial < AnrIntegrationOptions > ) => IntegrationFnResult & AnrInternal ;
76+
77+ export const anrIntegration = defineIntegration ( _anrIntegration ) as AnrReturn ;
5078
5179/**
5280 * Starts the ANR worker thread
81+ *
82+ * @returns A function to stop the worker
5383 */
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 > {
5688 const dsn = client . getDsn ( ) ;
5789
5890 if ( ! dsn ) {
59- return ;
91+ return ( ) => {
92+ //
93+ } ;
6094 }
6195
96+ const contexts = await getContexts ( client ) ;
97+
6298 // These will not be accurate if sent later from the worker thread
6399 delete contexts . app ?. app_memory ;
64100 delete contexts . device ?. free_memory ;
@@ -78,11 +114,11 @@ async function _startWorker(client: NodeClient, _options: Partial<AnrIntegration
78114 release : initOptions . release ,
79115 dist : initOptions . dist ,
80116 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 || { } ,
86122 contexts,
87123 } ;
88124
@@ -135,4 +171,9 @@ async function _startWorker(client: NodeClient, _options: Partial<AnrIntegration
135171
136172 // Ensure this thread can't block app exit
137173 worker . unref ( ) ;
174+
175+ return ( ) => {
176+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
177+ worker . terminate ( ) ;
178+ } ;
138179}
0 commit comments