Skip to content

Commit 3b75594

Browse files
LekoArtspieh
andauthored
feat(gatsby-worker): Show original stack trace (#37206)
Co-authored-by: Michal Piechowiak <[email protected]>
1 parent e2192c5 commit 3b75594

File tree

10 files changed

+224
-52
lines changed

10 files changed

+224
-52
lines changed

packages/gatsby-worker/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
},
99
"dependencies": {
1010
"@babel/core": "^7.15.5",
11-
"@babel/runtime": "^7.15.4"
11+
"@babel/runtime": "^7.15.4",
12+
"fs-extra": "^10.0.0",
13+
"signal-exit": "^3.0.5"
1214
},
1315
"devDependencies": {
1416
"@babel/cli": "^7.15.4",

packages/gatsby-worker/src/__tests__/fixtures/test-child.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,12 @@ interface IPingMessage {
8282
type: `PING`
8383
}
8484

85-
export type MessagesFromChild = IPingMessage
85+
interface ILotOfMessagesTestMessage {
86+
type: `LOT_OF_MESSAGES_TEST`
87+
payload: number
88+
}
89+
90+
export type MessagesFromChild = IPingMessage | ILotOfMessagesTestMessage
8691

8792
interface IPongMessage {
8893
type: `PONG`
@@ -97,6 +102,10 @@ let getWasPonged = function (): boolean {
97102
throw new Error(`gatsby-worker messenger not available`)
98103
}
99104

105+
let lotOfMessagesAndExit = function (count: number): void {
106+
throw new Error(`gatsby-worker messenger not available`)
107+
}
108+
100109
const messenger = getMessenger<MessagesFromParent, MessagesFromChild>()
101110
if (messenger) {
102111
let wasPonged = false
@@ -126,6 +135,13 @@ if (messenger) {
126135
getWasPonged = function getWasPonged(): boolean {
127136
return wasPonged
128137
}
138+
139+
lotOfMessagesAndExit = function lotOfMessagesAndExit(count: number): boolean {
140+
for (let i = 0; i < count; i++) {
141+
messenger.sendMessage({ type: `LOT_OF_MESSAGES_TEST`, payload: i })
142+
}
143+
process.exit(1)
144+
}
129145
}
130146

131-
export { setupPingPongMessages, getWasPonged }
147+
export { setupPingPongMessages, getWasPonged, lotOfMessagesAndExit }

packages/gatsby-worker/src/__tests__/integration.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ describe(`gatsby-worker`, () => {
3636
fail(`worker pool not created`)
3737
}
3838

39-
const exposedMethodsSingle = Object.keys(workerPool.single)
40-
const exposedMethodsAll = Object.keys(workerPool.all)
39+
const exposedMethodsSingle = Object.keys(workerPool.single).sort()
40+
const exposedMethodsAll = Object.keys(workerPool.all).sort()
4141
// we expect that `notAFunction` even tho is exported in child module is not exposed
4242
// as it's not a function
4343
expect(exposedMethodsSingle).toMatchInlineSnapshot(`
@@ -46,6 +46,7 @@ describe(`gatsby-worker`, () => {
4646
"async100ms",
4747
"asyncThrow",
4848
"getWasPonged",
49+
"lotOfMessagesAndExit",
4950
"neverEnding",
5051
"pid",
5152
"setupPingPongMessages",
@@ -426,5 +427,27 @@ describe(`gatsby-worker`, () => {
426427
workerPool.sendMessage({ type: `PONG` }, 9001)
427428
}).toThrowError(`There is no worker with "9001" id.`)
428429
})
430+
431+
it(`messages are not lost if worker exits soon after sending a message`, async () => {
432+
if (!workerPool) {
433+
fail(`worker pool not created`)
434+
}
435+
const COUNT = 10000
436+
437+
let counter = 0
438+
workerPool.onMessage(msg => {
439+
if (msg.type === `LOT_OF_MESSAGES_TEST`) {
440+
counter++
441+
}
442+
})
443+
444+
try {
445+
await workerPool.single.lotOfMessagesAndExit(COUNT)
446+
} catch (e) {
447+
console.log(e)
448+
}
449+
450+
expect(counter).toEqual(COUNT)
451+
})
429452
})
430453
})

packages/gatsby-worker/src/child.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import signalExit from "signal-exit"
2+
import fs from "fs-extra"
13
import {
24
ParentMessageUnion,
35
ChildMessageUnion,
@@ -10,6 +12,7 @@ import {
1012
} from "./types"
1113
import { isPromise } from "./utils"
1214

15+
let counter = 0
1316
export interface IGatsbyWorkerMessenger<
1417
MessagesFromParent = unknown,
1518
MessagesFromChild = MessagesFromParent
@@ -30,12 +33,35 @@ let getMessenger = function <
3033
return undefined
3134
}
3235

33-
if (process.send && process.env.GATSBY_WORKER_MODULE_PATH) {
36+
if (
37+
process.send &&
38+
process.env.GATSBY_WORKER_MODULE_PATH &&
39+
process.env.GATSBY_WORKER_IN_FLIGHT_DUMP_LOCATION
40+
) {
41+
const workerInFlightsDumpLocation =
42+
process.env.GATSBY_WORKER_IN_FLIGHT_DUMP_LOCATION
3443
isWorker = true
3544
const listeners: Array<(msg: any) => void> = []
36-
const ensuredSendToMain = process.send.bind(process) as (
37-
msg: ChildMessageUnion
38-
) => void
45+
46+
const inFlightMessages = new Set<ChildMessageUnion>()
47+
signalExit(() => {
48+
if (inFlightMessages.size > 0) {
49+
// this need to be sync
50+
fs.outputJsonSync(
51+
workerInFlightsDumpLocation,
52+
Array.from(inFlightMessages)
53+
)
54+
}
55+
})
56+
57+
function ensuredSendToMain(msg: ChildMessageUnion): void {
58+
inFlightMessages.add(msg)
59+
process.send!(msg, undefined, undefined, error => {
60+
if (!error) {
61+
inFlightMessages.delete(msg)
62+
}
63+
})
64+
}
3965

4066
function onError(error: Error): void {
4167
if (error == null) {
@@ -44,6 +70,7 @@ if (process.send && process.env.GATSBY_WORKER_MODULE_PATH) {
4470

4571
const msg: ChildMessageUnion = [
4672
ERROR,
73+
++counter,
4774
error.constructor && error.constructor.name,
4875
error.message,
4976
error.stack,
@@ -54,7 +81,7 @@ if (process.send && process.env.GATSBY_WORKER_MODULE_PATH) {
5481
}
5582

5683
function onResult(result: unknown): void {
57-
const msg: ChildMessageUnion = [RESULT, result]
84+
const msg: ChildMessageUnion = [RESULT, ++counter, result]
5885
ensuredSendToMain(msg)
5986
}
6087

@@ -69,7 +96,7 @@ if (process.send && process.env.GATSBY_WORKER_MODULE_PATH) {
6996
listeners.push(listener)
7097
},
7198
sendMessage(msg: MessagesFromChild): void {
72-
const poolMsg: ChildMessageUnion = [CUSTOM_MESSAGE, msg]
99+
const poolMsg: ChildMessageUnion = [CUSTOM_MESSAGE, ++counter, msg]
73100
ensuredSendToMain(poolMsg)
74101
},
75102
messagingVersion: MESSAGING_VERSION,
@@ -82,7 +109,7 @@ if (process.send && process.env.GATSBY_WORKER_MODULE_PATH) {
82109
if (msg[0] === EXECUTE) {
83110
let result
84111
try {
85-
result = child[msg[1]].call(child, ...msg[2])
112+
result = child[msg[2]].call(child, ...msg[3])
86113
} catch (e) {
87114
onError(e)
88115
return
@@ -97,14 +124,14 @@ if (process.send && process.env.GATSBY_WORKER_MODULE_PATH) {
97124
process.off(`message`, messageHandler)
98125
} else if (msg[0] === CUSTOM_MESSAGE) {
99126
for (const listener of listeners) {
100-
listener(msg[1])
127+
listener(msg[2])
101128
}
102129
}
103130
}
104131

105132
process.on(`message`, messageHandler)
106133

107-
ensuredSendToMain([WORKER_READY])
134+
ensuredSendToMain([WORKER_READY, ++counter])
108135
}
109136

110137
export { isWorker, getMessenger }

0 commit comments

Comments
 (0)