Skip to content

Commit

Permalink
fix: defer errors with setImmediate (#3081)
Browse files Browse the repository at this point in the history
  • Loading branch information
ronag authored Apr 10, 2024
1 parent fe44b9b commit b482512
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 21 deletions.
4 changes: 1 addition & 3 deletions lib/api/readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ class BodyReadable extends Readable {
// tick as it is created, then a user who is waiting for a
// promise (i.e micro tick) for installing a 'error' listener will
// never get a chance and will always encounter an unhandled exception.
// - tick => process.nextTick(fn)
// - micro tick => queueMicrotask(fn)
queueMicrotask(() => {
setImmediate(() => {
callback(err)
})
}
Expand Down
90 changes: 72 additions & 18 deletions test/request-timeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ test('request timeout with readable body', async (t) => {
test('body timeout', async (t) => {
t = tspl(t, { plan: 2 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -102,7 +105,10 @@ test('body timeout', async (t) => {
test('overridden request timeout', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -136,7 +142,10 @@ test('overridden request timeout', async (t) => {
test('overridden body timeout', async (t) => {
t = tspl(t, { plan: 2 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -172,7 +181,10 @@ test('overridden body timeout', async (t) => {
test('With EE signal', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -209,7 +221,10 @@ test('With EE signal', async (t) => {
test('With abort-controller signal', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -246,7 +261,10 @@ test('With abort-controller signal', async (t) => {
test('Abort before timeout (EE)', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -283,7 +301,10 @@ test('Abort before timeout (EE)', async (t) => {
test('Abort before timeout (abort-controller)', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -320,7 +341,10 @@ test('Abort before timeout (abort-controller)', async (t) => {
test('Timeout with pipelining', async (t) => {
t = tspl(t, { plan: 3 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -363,7 +387,10 @@ test('Timeout with pipelining', async (t) => {
test('Global option', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -399,7 +426,10 @@ test('Global option', async (t) => {
test('Request options overrides global option', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -460,7 +490,10 @@ test('client.destroy should cancel the timeout', async (t) => {
test('client.close should wait for the timeout', async (t) => {
t = tspl(t, { plan: 2 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -542,7 +575,10 @@ test('Validation', async (t) => {
test('Disable request timeout', async (t) => {
t = tspl(t, { plan: 2 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -586,7 +622,10 @@ test('Disable request timeout', async (t) => {
test('Disable request timeout for a single request', async (t) => {
t = tspl(t, { plan: 2 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -630,7 +669,10 @@ test('Disable request timeout for a single request', async (t) => {
test('stream timeout', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -668,7 +710,10 @@ test('stream timeout', async (t) => {
test('stream custom timeout', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -708,7 +753,10 @@ test('stream custom timeout', async (t) => {
test('pipeline timeout', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -765,7 +813,10 @@ test('pipeline timeout', async (t) => {
test('pipeline timeout', async (t) => {
t = tspl(t, { plan: 1 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down Expand Up @@ -824,7 +875,10 @@ test('pipeline timeout', async (t) => {
test('client.close should not deadlock', async (t) => {
t = tspl(t, { plan: 2 })

const clock = FakeTimers.install({ shouldClearNativeTimers: true })
const clock = FakeTimers.install({
shouldClearNativeTimers: true,
toFake: ['setTimeout', 'clearTimeout']
})
after(() => clock.uninstall())

const orgTimers = { ...timers }
Expand Down

0 comments on commit b482512

Please sign in to comment.