diff --git a/dev-packages/node-core-integration-tests/suites/anr/app-path.mjs b/dev-packages/node-core-integration-tests/suites/anr/app-path.mjs index 1c5f141021a8..d009c31b7345 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/app-path.mjs +++ b/dev-packages/node-core-integration-tests/suites/anr/app-path.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node-core'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import * as path from 'path'; import * as url from 'url'; import { setupOtel } from '../../utils/setupOtel.js'; @@ -26,11 +24,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/basic-multiple.mjs b/dev-packages/node-core-integration-tests/suites/anr/basic-multiple.mjs index 6b0e1de340dd..2dbc03f53b33 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/basic-multiple.mjs +++ b/dev-packages/node-core-integration-tests/suites/anr/basic-multiple.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node-core'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { setupOtel } from '../../utils/setupOtel.js'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; @@ -22,11 +20,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/basic-session.js b/dev-packages/node-core-integration-tests/suites/anr/basic-session.js index 229f4eb28d5b..76aab6edc324 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/basic-session.js +++ b/dev-packages/node-core-integration-tests/suites/anr/basic-session.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node-core'); const { setupOtel } = require('../../utils/setupOtel.js'); const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); @@ -21,11 +18,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/basic.js b/dev-packages/node-core-integration-tests/suites/anr/basic.js index d02ed4f254f1..248b0a466390 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/basic.js +++ b/dev-packages/node-core-integration-tests/suites/anr/basic.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node-core'); const { setupOtel } = require('../../utils/setupOtel.js'); const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); @@ -23,11 +20,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/basic.mjs b/dev-packages/node-core-integration-tests/suites/anr/basic.mjs index 71525c7e9ebe..cb75d9a343c8 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/basic.mjs +++ b/dev-packages/node-core-integration-tests/suites/anr/basic.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node-core'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { setupOtel } from '../../utils/setupOtel.js'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; @@ -22,11 +20,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/forked.js b/dev-packages/node-core-integration-tests/suites/anr/forked.js index 5dd6c93e82ef..99a0c151a0ad 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/forked.js +++ b/dev-packages/node-core-integration-tests/suites/anr/forked.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node-core'); const { setupOtel } = require('../../utils/setupOtel.js'); const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); @@ -22,11 +19,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/indefinite.mjs b/dev-packages/node-core-integration-tests/suites/anr/indefinite.mjs index 0b8d33757e90..8c83d5f15be6 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/indefinite.mjs +++ b/dev-packages/node-core-integration-tests/suites/anr/indefinite.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node-core'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { setupOtel } from '../../utils/setupOtel.js'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; @@ -20,12 +18,11 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - // This loop will run almost indefinitely + let n = 1; for (let i = 0; i < 2000000000; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-core-integration-tests/suites/anr/isolated.mjs b/dev-packages/node-core-integration-tests/suites/anr/isolated.mjs index 8d24c4cbd021..8205e74142d4 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/isolated.mjs +++ b/dev-packages/node-core-integration-tests/suites/anr/isolated.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node-core'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { setupOtel } from '../../utils/setupOtel.js'; setTimeout(() => { @@ -18,11 +16,16 @@ setupOtel(client); async function longWork() { await new Promise(resolve => setTimeout(resolve, 1000)); - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } function neverResolve() { diff --git a/dev-packages/node-core-integration-tests/suites/anr/stop-and-start.js b/dev-packages/node-core-integration-tests/suites/anr/stop-and-start.js index bec3d83b7d39..1038423b172d 100644 --- a/dev-packages/node-core-integration-tests/suites/anr/stop-and-start.js +++ b/dev-packages/node-core-integration-tests/suites/anr/stop-and-start.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node-core'); const { setupOtel } = require('../../utils/setupOtel.js'); @@ -23,19 +20,29 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWorkIgnored() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } function longWork() { - for (let i = 0; i < 50; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } setTimeout(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/app-path.mjs b/dev-packages/node-integration-tests/suites/anr/app-path.mjs index e0a13f7e6869..8fcb638aeaae 100644 --- a/dev-packages/node-integration-tests/suites/anr/app-path.mjs +++ b/dev-packages/node-integration-tests/suites/anr/app-path.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import * as path from 'path'; import * as url from 'url'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; @@ -23,11 +21,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/basic-multiple.mjs b/dev-packages/node-integration-tests/suites/anr/basic-multiple.mjs index a8b0aa0b7c5d..71a0f21b18f5 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic-multiple.mjs +++ b/dev-packages/node-integration-tests/suites/anr/basic-multiple.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; global._sentryDebugIds = { [new Error().stack]: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa' }; @@ -19,11 +17,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/basic-session.js b/dev-packages/node-integration-tests/suites/anr/basic-session.js index 8658c465adc9..70a814e0312c 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic-session.js +++ b/dev-packages/node-integration-tests/suites/anr/basic-session.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node'); const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); @@ -18,11 +15,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/basic.js b/dev-packages/node-integration-tests/suites/anr/basic.js index 61b394c630e2..bb0ba6d54d3d 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic.js +++ b/dev-packages/node-integration-tests/suites/anr/basic.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node'); const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); @@ -20,11 +17,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/basic.mjs b/dev-packages/node-integration-tests/suites/anr/basic.mjs index 20737c93c5f2..967a1ae7b132 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic.mjs +++ b/dev-packages/node-integration-tests/suites/anr/basic.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; global._sentryDebugIds = { [new Error().stack]: 'aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaa' }; @@ -19,11 +17,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/forked.js b/dev-packages/node-integration-tests/suites/anr/forked.js index 1abed46c7b68..080ae1ed029d 100644 --- a/dev-packages/node-integration-tests/suites/anr/forked.js +++ b/dev-packages/node-integration-tests/suites/anr/forked.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node'); const { waitForDebuggerReady } = require('@sentry-internal/test-utils'); @@ -19,11 +16,16 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/indefinite.mjs b/dev-packages/node-integration-tests/suites/anr/indefinite.mjs index 849e35903e14..4b3b4c2787e7 100644 --- a/dev-packages/node-integration-tests/suites/anr/indefinite.mjs +++ b/dev-packages/node-integration-tests/suites/anr/indefinite.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; import { waitForDebuggerReady } from '@sentry-internal/test-utils'; setTimeout(() => { @@ -17,12 +15,11 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWork() { - // This loop will run almost indefinitely + let n = 1; for (let i = 0; i < 2000000000; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } waitForDebuggerReady(() => { diff --git a/dev-packages/node-integration-tests/suites/anr/isolated.mjs b/dev-packages/node-integration-tests/suites/anr/isolated.mjs index c0ca76da4319..95452f723b93 100644 --- a/dev-packages/node-integration-tests/suites/anr/isolated.mjs +++ b/dev-packages/node-integration-tests/suites/anr/isolated.mjs @@ -1,6 +1,4 @@ import * as Sentry from '@sentry/node'; -import * as assert from 'assert'; -import * as crypto from 'crypto'; setTimeout(() => { process.exit(); @@ -15,11 +13,16 @@ Sentry.init({ async function longWork() { await new Promise(resolve => setTimeout(resolve, 1000)); - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } function neverResolve() { diff --git a/dev-packages/node-integration-tests/suites/anr/stop-and-start.js b/dev-packages/node-integration-tests/suites/anr/stop-and-start.js index b833dfde5eb6..b49c1c6a3940 100644 --- a/dev-packages/node-integration-tests/suites/anr/stop-and-start.js +++ b/dev-packages/node-integration-tests/suites/anr/stop-and-start.js @@ -1,6 +1,3 @@ -const crypto = require('crypto'); -const assert = require('assert'); - const Sentry = require('@sentry/node'); setTimeout(() => { @@ -20,19 +17,29 @@ Sentry.setUser({ email: 'person@home.com' }); Sentry.addBreadcrumb({ message: 'important message!' }); function longWorkIgnored() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } function longWork() { - for (let i = 0; i < 20; i++) { - const salt = crypto.randomBytes(128).toString('base64'); - const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); - assert.ok(hash); + // Busy-block the event loop with pure-JS work. The ANR worker samples the main thread via the + // inspector, which can only pause at a JS safepoint; inside a native call like `crypto.pbkdf2Sync` + // the pause resolves only after the call returns, so the sample can miss `longWork` and land in + // timer internals instead. Pure-JS work keeps `longWork` on the sampled stack for the whole block. + const start = Date.now(); + let n = 1; + while (Date.now() - start < 1000) { + n = (n * 1103515245 + 12345) % 2147483648; } + return n; } setTimeout(() => {