Skip to content

Commit 5bdef4a

Browse files
gatsbybotTylerBarnespieh
authored
fix(gatsby): don't block event loop during inference (#37780) (#37801)
Don't block the event loop during inference (cherry picked from commit c08048d) Co-authored-by: Tyler Barnes <[email protected]> Co-authored-by: Michal Piechowiak <[email protected]>
1 parent 50e3f94 commit 5bdef4a

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

packages/gatsby/src/redux/reducers/inference-metadata.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ const incrementalReducer = (
3737

3838
case `BUILD_TYPE_METADATA`: {
3939
// Overwrites existing metadata
40-
const { nodes, typeName } = action.payload
40+
const { nodes, typeName, clearExistingMetadata } = action.payload
4141
if (!state[typeName]?.ignored) {
42-
state[typeName] = addNodes(initialTypeMetadata(), nodes)
42+
const initialMetadata =
43+
clearExistingMetadata || !state[typeName]
44+
? initialTypeMetadata()
45+
: state[typeName]
46+
47+
state[typeName] = addNodes(initialMetadata, nodes)
4348
}
4449
return state
4550
}

packages/gatsby/src/redux/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ interface IBuildTypeMetadataAction {
895895
type: `BUILD_TYPE_METADATA`
896896
payload: {
897897
nodes: Array<IGatsbyNode>
898+
clearExistingMetadata: boolean
898899
typeName: string
899900
}
900901
}

packages/gatsby/src/schema/index.js

+40-10
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,48 @@ const buildInferenceMetadata = ({ types }) =>
6060
// TODO: use async iterators when we switch to node>=10
6161
// or better investigate if we can offload metadata building to worker/Jobs API
6262
// and then feed the result into redux?
63-
const processNextType = () => {
63+
const processNextType = async () => {
6464
const typeName = typeNames.pop()
65-
store.dispatch({
66-
type: `BUILD_TYPE_METADATA`,
67-
payload: {
68-
typeName,
69-
nodes: getDataStore().iterateNodesByType(typeName),
70-
},
71-
})
65+
66+
let processingNodes = []
67+
let dispatchCount = 0
68+
function dispatchNodes() {
69+
return new Promise(res => {
70+
store.dispatch({
71+
type: `BUILD_TYPE_METADATA`,
72+
payload: {
73+
typeName,
74+
// only clear metadata on the first chunk for this type
75+
clearExistingMetadata: dispatchCount++ === 0,
76+
nodes: processingNodes,
77+
},
78+
})
79+
setImmediate(() => {
80+
// clear this array after BUILD_TYPE_METADATA reducer has synchronously run
81+
processingNodes = []
82+
// dont block the event loop. node may decide to free previous processingNodes array from memory if it needs to.
83+
setImmediate(() => {
84+
res(null)
85+
})
86+
})
87+
})
88+
}
89+
90+
for (const node of getDataStore().iterateNodesByType(typeName)) {
91+
processingNodes.push(node)
92+
93+
if (processingNodes.length > 1000) {
94+
await dispatchNodes()
95+
}
96+
}
97+
98+
if (processingNodes.length > 0) {
99+
await dispatchNodes()
100+
}
101+
72102
if (typeNames.length > 0) {
73-
// Give event-loop a break
74-
setTimeout(processNextType, 0)
103+
// dont block the event loop
104+
setImmediate(() => processNextType())
75105
} else {
76106
resolve()
77107
}

0 commit comments

Comments
 (0)