Skip to content

Commit

Permalink
chore(gatsby): refactor of query-runner.ts (#27854)
Browse files Browse the repository at this point in the history
* no-const-arrow

* Move startQueryJob out to module global space

* Create global function for long running query warning

* Make use of async syntax properly

* Abstract error panic in its own func

* A worthy comment

Co-authored-by: gatsbybot <mathews.kyle+gatsbybot@gmail.com>
  • Loading branch information
pvdz and gatsbybot committed Nov 6, 2020
1 parent 995c0dc commit 051e1aa
Showing 1 changed file with 87 additions and 80 deletions.
167 changes: 87 additions & 80 deletions packages/gatsby/src/query/query-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import _ from "lodash"
import fs from "fs-extra"
import report from "gatsby-cli/lib/reporter"
import crypto from "crypto"
import { ExecutionResult } from "graphql"
import { ExecutionResult, GraphQLError } from "graphql"

import path from "path"
import { store } from "../redux"
Expand All @@ -27,53 +27,94 @@ interface IQueryJob {
pluginCreatorId: string
}

// Run query
export const queryRunner = async (
function reportLongRunningQueryJob(queryJob): void {
const messageParts = [
`Query takes too long:`,
`File path: ${queryJob.componentPath}`,
]

if (queryJob.isPage) {
const { path, context } = queryJob.context
messageParts.push(`URL path: ${path}`)

if (!_.isEmpty(context)) {
messageParts.push(`Context: ${JSON.stringify(context, null, 4)}`)
}
}

report.warn(messageParts.join(`\n`))
}

function panicQueryJobError(
queryJob: IQueryJob,
errors: ReadonlyArray<GraphQLError>
): void {
let urlPath = undefined
let queryContext = {}
const plugin = queryJob.pluginCreatorId || `none`

if (queryJob.isPage) {
urlPath = queryJob.context.path
queryContext = queryJob.context.context
}

const structuredErrors = errors.map(e => {
const structuredError = errorParser({
message: e.message,
filePath: undefined,
location: undefined,
})

structuredError.context = {
...structuredError.context,
codeFrame: getCodeFrame(
queryJob.query,
e.locations && e.locations[0].line,
e.locations && e.locations[0].column
),
filePath: queryJob.componentPath,
...(urlPath ? { urlPath } : {}),
...queryContext,
plugin,
}

return structuredError
})

report.panicOnBuild(structuredErrors)
}

async function startQueryJob(
graphqlRunner: GraphQLRunner,
queryJob: IQueryJob,
parentSpan: Span | undefined
): Promise<IExecutionResult> => {
const { program } = store.getState()
): Promise<ExecutionResult> {
let isPending = true

// Print out warning when query takes too long
const timeoutId = setTimeout(() => {
if (isPending) {
reportLongRunningQueryJob(queryJob)
}
}, 15000)

const graphql = (
query: string,
context: Record<string, unknown>,
queryName: string
): Promise<ExecutionResult> => {
// Check if query takes too long, print out warning
const promise = graphqlRunner.query(query, context, {
try {
return await graphqlRunner.query(queryJob.query, queryJob.context, {
parentSpan,
queryName,
queryName: queryJob.id,
})
let isPending = true

const timeoutId = setTimeout(() => {
if (isPending) {
const messageParts = [
`Query takes too long:`,
`File path: ${queryJob.componentPath}`,
]

if (queryJob.isPage) {
const { path, context } = queryJob.context
messageParts.push(`URL path: ${path}`)

if (!_.isEmpty(context)) {
messageParts.push(`Context: ${JSON.stringify(context, null, 4)}`)
}
}

report.warn(messageParts.join(`\n`))
}
}, 15000)

promise.finally(() => {
isPending = false
clearTimeout(timeoutId)
})

return promise
} finally {
isPending = false
clearTimeout(timeoutId)
}
}

export async function queryRunner(
graphqlRunner: GraphQLRunner,
queryJob: IQueryJob,
parentSpan: Span | undefined
): Promise<IExecutionResult> {
const { program } = store.getState()

boundActionCreators.queryStart({
path: queryJob.id,
Expand All @@ -87,47 +128,12 @@ export const queryRunner = async (
if (!queryJob.query || queryJob.query === ``) {
result = {}
} else {
result = await graphql(queryJob.query, queryJob.context, queryJob.id)
result = await startQueryJob(graphqlRunner, queryJob, parentSpan)
}

// If there's a graphql error then log the error. If we're building, also
// quit.
if (result && result.errors) {
let urlPath = undefined
let queryContext = {}
const plugin = queryJob.pluginCreatorId || `none`

if (queryJob.isPage) {
urlPath = queryJob.context.path
queryContext = queryJob.context.context
}

const structuredErrors = result.errors
.map(e => {
const structuredError = errorParser({
message: e.message,
filePath: undefined,
location: undefined,
})

structuredError.context = {
...structuredError.context,
codeFrame: getCodeFrame(
queryJob.query,
e.locations && e.locations[0].line,
e.locations && e.locations[0].column
),
filePath: queryJob.componentPath,
...(urlPath ? { urlPath } : {}),
...queryContext,
plugin,
}

return structuredError
})
.filter(Boolean)

report.panicOnBuild(structuredErrors)
if (result.errors) {
// If there's a graphql error then log the error and exit
panicQueryJobError(queryJob, result.errors)
}

// Add the page context onto the results.
Expand Down Expand Up @@ -191,6 +197,7 @@ export const queryRunner = async (
}
}

// Broadcast that a page's query has run.
boundActionCreators.pageQueryRun({
path: queryJob.id,
componentPath: queryJob.componentPath,
Expand Down

0 comments on commit 051e1aa

Please sign in to comment.