Skip to content

Commit

Permalink
fix(gatsby-plugin-gatsby-cloud): add backpressure for IPC (#32963)
Browse files Browse the repository at this point in the history
* fix(gatsby-plugin-gatsby-cloud): add backpressure for IPC

* fix tests
  • Loading branch information
vladar committed Sep 1, 2021
1 parent 3afef0a commit eb1f568
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 174 deletions.
Expand Up @@ -319,15 +319,18 @@ describe(`build-headers-program`, () => {
process.send = jest.fn()
await buildHeadersProgram(pluginData, pluginOptions)

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_HEADER_ENTRY`,
payload: {
url: `/hello`,
headers: [`X-Frame-Options: SAMEORIGIN`],
expect(process.send).toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_HEADER_ENTRY`,
payload: {
url: `/hello`,
headers: [`X-Frame-Options: SAMEORIGIN`],
},
},
},
})
expect.any(Function)
)
})
})
Expand Up @@ -269,27 +269,33 @@ describe(`create-redirects`, () => {
]
)

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_REDIRECT_ENTRY`,
payload: {
fromPath: `/old-url`,
toPath: `/new-url`,
isPermanent: true,
expect(process.send).toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_REDIRECT_ENTRY`,
payload: {
fromPath: `/old-url`,
toPath: `/new-url`,
isPermanent: true,
},
},
},
})
expect.any(Function)
)

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_REWRITE_ENTRY`,
payload: {
fromPath: `/url_that_is/ugly`,
toPath: `/not_ugly/url`,
expect(process.send).toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_REWRITE_ENTRY`,
payload: {
fromPath: `/url_that_is/ugly`,
toPath: `/not_ugly/url`,
},
},
},
})
expect.any(Function)
)
})
})
144 changes: 56 additions & 88 deletions packages/gatsby-plugin-gatsby-cloud/src/__tests__/routes.js
Expand Up @@ -64,111 +64,79 @@ describe(`Routes IPC`, () => {
)

if (os.platform() !== `win32`) {
expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"index.html": `DSR`,
"page-data/index/page-data.json": `DSR`,
},
},
},
})

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path/1/index.html": `DSR`,
"page-data/path/1/page-data.json": `DSR`,
},
},
},
})

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path/2/index.html": `SSR`,
"page-data/path/2/page-data.json": `SSR`,
expect(process.send).toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"index.html": `DSR`,
"page-data/index/page-data.json": `DSR`,
"path/1/index.html": `DSR`,
"page-data/path/1/page-data.json": `DSR`,
"path/2/index.html": `SSR`,
"page-data/path/2/page-data.json": `SSR`,
},
},
},
},
})
expect.any(Function)
)

expect(process.send).not.toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path/3/index.html": `SSG`,
"page-data/path/3/page-data.json": `SSG`,
expect(process.send).not.toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path/3/index.html": `SSG`,
"page-data/path/3/page-data.json": `SSG`,
},
},
},
},
})
expect.any(Function)
)
}

if (os.platform() === `win32`) {
expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"index.html": `DSR`,
"page-data\\index\\page-data.json": `DSR`,
},
},
},
})

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path\\1\\index.html": `DSR`,
"page-data\\path\\1\\page-data.json": `DSR`,
},
},
},
})

expect(process.send).toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path\\2\\index.html": `SSR`,
"page-data\\path\\2\\page-data.json": `SSR`,
expect(process.send).toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"index.html": `DSR`,
"page-data\\index\\page-data.json": `DSR`,
"path\\1\\index.html": `DSR`,
"page-data\\path\\1\\page-data.json": `DSR`,
"path\\2\\index.html": `SSR`,
"page-data\\path\\2\\page-data.json": `SSR`,
},
},
},
},
})
expect.any(Function)
)

expect(process.send).not.toHaveBeenCalledWith({
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path\\3\\index.html": `SSG`,
"page-data\\path\\3\\page-data.json": `SSG`,
expect(process.send).not.toHaveBeenCalledWith(
{
type: `LOG_ACTION`,
action: {
type: `CREATE_ROUTE`,
payload: {
routes: {
"path\\3\\index.html": `SSG`,
"page-data\\path\\3\\page-data.json": `SSG`,
},
},
},
},
})
expect.any(Function)
)
}
})
})
72 changes: 41 additions & 31 deletions packages/gatsby-plugin-gatsby-cloud/src/build-headers-program.js
Expand Up @@ -310,40 +310,50 @@ const applyTransfromHeaders =
headers =>
_.mapValues(headers, transformHeaders)

const writeHeadersFile =
({ publicFolder }) =>
contents =>
new Promise((resolve, reject) => {
/**
* Emit Headers via IPC
*/
Object.entries(contents).map(([k, val]) => {
emitHeaders({
url: k,
headers: val,
})
})
const sendHeadersViaIPC = async headers => {
/**
* Emit Headers via IPC
*/
let lastMessage
Object.entries(headers).forEach(([k, val]) => {
lastMessage = emitHeaders({
url: k,
headers: val,
})
})
await lastMessage
}

const contentsStr = JSON.stringify(contents)
const writeStream = createWriteStream(publicFolder(HEADERS_FILENAME))
const chunkSize = 10000
const numChunks = Math.ceil(contentsStr.length / chunkSize)

for (let i = 0; i < numChunks; i++) {
writeStream.write(
contentsStr.slice(
i * chunkSize,
Math.min((i + 1) * chunkSize, contentsStr.length)
)
const writeHeadersFile = async (publicFolder, contents) =>
new Promise((resolve, reject) => {
const contentsStr = JSON.stringify(contents)
const writeStream = createWriteStream(publicFolder(HEADERS_FILENAME))
const chunkSize = 10000
const numChunks = Math.ceil(contentsStr.length / chunkSize)

for (let i = 0; i < numChunks; i++) {
writeStream.write(
contentsStr.slice(
i * chunkSize,
Math.min((i + 1) * chunkSize, contentsStr.length)
)
}
)
}

writeStream.end()
writeStream.on(`finish`, () => {
resolve()
})
writeStream.on(`error`, reject)
writeStream.end()
writeStream.on(`finish`, () => {
resolve()
})
writeStream.on(`error`, reject)
})

const saveHeaders =
({ publicFolder }) =>
contents =>
Promise.all([
sendHeadersViaIPC(contents),
writeHeadersFile(publicFolder, contents),
])

export default function buildHeadersProgram(pluginData, pluginOptions) {
return _.flow(
Expand All @@ -353,6 +363,6 @@ export default function buildHeadersProgram(pluginData, pluginOptions) {
mapUserLinkAllPageHeaders(pluginData, pluginOptions),
applyLinkHeaders(pluginData, pluginOptions),
applyTransfromHeaders(pluginOptions),
writeHeadersFile(pluginData)
saveHeaders(pluginData)
)(pluginOptions.headers)
}
8 changes: 6 additions & 2 deletions packages/gatsby-plugin-gatsby-cloud/src/create-redirects.js
Expand Up @@ -29,17 +29,21 @@ export default async function writeRedirectsFile(
/**
* IPC Emit for redirects
*/
let lastMessageSent
redirects.forEach(redirect => {
emitRedirects(redirect)
lastMessageSent = emitRedirects(redirect)
})

/**
* IPC Emit for rewrites
*/
rewrites.forEach(rewrite => {
emitRewrites(rewrite)
lastMessageSent = emitRewrites(rewrite)
})

// This prevents process from exiting before handling the last IPC message
await lastMessageSent

// Is it ok to pass through the data or should we format it so that we don't have dependencies
// between the redirects and rewrites formats? What are the chances those will change?
const FILE_PATH = publicFolder(REDIRECTS_FILENAME)
Expand Down

0 comments on commit eb1f568

Please sign in to comment.