-
Notifications
You must be signed in to change notification settings - Fork 10.3k
refactor(gatsby): Make query queue constructable #13061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cc71544
1b5f5f5
552b7a4
a95a108
76d56ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,20 @@ | ||
| // @flow | ||
|
|
||
| import type { QueryJob } from "../query-runner" | ||
|
|
||
| /** | ||
| * Jobs of this module | ||
| * - Ensure on bootstrap that all invalid page queries are run and report | ||
| * when this is done | ||
| * - Watch for when a page's query is invalidated and re-run it. | ||
| */ | ||
|
|
||
| const _ = require(`lodash`) | ||
|
|
||
| const queue = require(`./query-queue`) | ||
| const Queue = require(`better-queue`) | ||
| const convertHrtime = require(`convert-hrtime`) | ||
| const { store, emitter } = require(`../redux`) | ||
| const queryQueue = require(`./queue`) | ||
|
|
||
| let queuedDirtyActions = [] | ||
|
|
||
| let active = false | ||
| let running = false | ||
|
|
||
| const runQueriesForPathnamesQueue = new Set() | ||
| exports.queueQueryForPathname = pathname => { | ||
| const queueQueryForPathname = pathname => { | ||
| runQueriesForPathnamesQueue.add(pathname) | ||
| } | ||
|
|
||
| // Do initial run of graphql queries during bootstrap. | ||
| // Afterwards we listen "API_RUNNING_QUEUE_EMPTY" and check | ||
| // for dirty nodes before running queries. | ||
| exports.runInitialQueries = async () => { | ||
| active = true | ||
| await runQueries(true) | ||
| return | ||
| } | ||
|
|
||
| const runQueries = async (initial = false) => { | ||
| // Don't run queries until bootstrap gets to "run graphql queries" | ||
| if (!active) { | ||
| return | ||
| } | ||
|
|
||
| const calcQueries = (initial = false) => { | ||
| // Find paths dependent on dirty nodes | ||
| queuedDirtyActions = _.uniq(queuedDirtyActions, a => a.payload.id) | ||
| const dirtyIds = findDirtyIds(queuedDirtyActions) | ||
|
|
@@ -71,13 +47,9 @@ const runQueries = async (initial = false) => { | |
|
|
||
| runQueriesForPathnamesQueue.clear() | ||
|
|
||
| // Run these paths | ||
| await runQueriesForPathnames(pathnamesToRun) | ||
| return | ||
| return pathnamesToRun | ||
| } | ||
|
|
||
| exports.runQueries = runQueries | ||
|
|
||
| emitter.on(`CREATE_NODE`, action => { | ||
| queuedDirtyActions.push(action) | ||
| }) | ||
|
|
@@ -86,26 +58,6 @@ emitter.on(`DELETE_NODE`, action => { | |
| queuedDirtyActions.push({ payload: action.payload }) | ||
| }) | ||
|
|
||
| const runQueuedActions = async () => { | ||
| if (active && !running) { | ||
| try { | ||
| running = true | ||
| await runQueries() | ||
| } finally { | ||
| running = false | ||
| if (queuedDirtyActions.length > 0) { | ||
| runQueuedActions() | ||
| } | ||
| } | ||
| } | ||
| } | ||
| exports.runQueuedActions = runQueuedActions | ||
|
|
||
| // Wait until all plugins have finished running (e.g. various | ||
| // transformer plugins) before running queries so we don't | ||
| // query things in a 1/2 finished state. | ||
| emitter.on(`API_RUNNING_QUEUE_EMPTY`, runQueuedActions) | ||
|
|
||
| let seenIdsWithoutDataDependencies = [] | ||
|
|
||
| // Remove pages from seenIdsWithoutDataDependencies when they're deleted | ||
|
|
@@ -147,10 +99,11 @@ const findIdsWithoutDataDependencies = () => { | |
| return notTrackedIds | ||
| } | ||
|
|
||
| const runQueriesForPathnames = pathnames => { | ||
| const makeQueryJobs = pathnames => { | ||
| const staticQueries = pathnames.filter(p => p.slice(0, 4) === `sq--`) | ||
| const pageQueries = pathnames.filter(p => p.slice(0, 4) !== `sq--`) | ||
| const state = store.getState() | ||
| const queryJobs = [] | ||
|
|
||
| staticQueries.forEach(id => { | ||
| const staticQueryComponent = store.getState().staticQueryComponents.get(id) | ||
|
|
@@ -162,16 +115,14 @@ const runQueriesForPathnames = pathnames => { | |
| componentPath: staticQueryComponent.componentPath, | ||
| context: { path: staticQueryComponent.jsonName }, | ||
| } | ||
| queue.push(queryJob) | ||
| queryJobs.push(queryJob) | ||
| }) | ||
|
|
||
| const pages = state.pages | ||
| let didNotQueueItems = true | ||
| pageQueries.forEach(id => { | ||
| const page = pages.get(id) | ||
| if (page) { | ||
| didNotQueueItems = false | ||
| queue.push( | ||
| queryJobs.push( | ||
| ({ | ||
| id: page.path, | ||
| jsonName: page.jsonName, | ||
|
|
@@ -186,18 +137,7 @@ const runQueriesForPathnames = pathnames => { | |
| ) | ||
| } | ||
| }) | ||
|
|
||
| if (didNotQueueItems || !pathnames || pathnames.length === 0) { | ||
| return Promise.resolve() | ||
| } | ||
|
|
||
| return new Promise(resolve => { | ||
| const onDrain = () => { | ||
| queue.removeListener(`drain`, onDrain) | ||
| resolve() | ||
| } | ||
| queue.on(`drain`, onDrain) | ||
| }) | ||
| return queryJobs | ||
| } | ||
|
|
||
| const findDirtyIds = actions => { | ||
|
|
@@ -221,3 +161,72 @@ const findDirtyIds = actions => { | |
| ) | ||
| return uniqDirties | ||
| } | ||
|
|
||
| const runInitialQueries = async activity => { | ||
| const pathnamesToRun = calcQueries(true) | ||
| if (pathnamesToRun.length === 0) { | ||
| return | ||
| } | ||
|
|
||
| const queryJobs = makeQueryJobs(pathnamesToRun) | ||
|
|
||
| const queue = queryQueue.makeBuild() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. calling it
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it makes sense within The other possibility I considered was to move
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like what you're thinking. Moving I'll just merge after testing and let's have a look afterwards. |
||
|
|
||
| const startQueries = process.hrtime() | ||
| queue.on(`task_finish`, () => { | ||
| const stats = queue.getStats() | ||
| activity.setStatus( | ||
| `${stats.total}/${stats.peak} ${( | ||
| stats.total / convertHrtime(process.hrtime(startQueries)).seconds | ||
| ).toFixed(2)} queries/second` | ||
| ) | ||
| }) | ||
| await queryQueue.processBatch(queue, queryJobs) | ||
| } | ||
|
|
||
| ///////////////////////////////////////////////////////////////////// | ||
| // Listener for gatsby develop | ||
|
|
||
| // Initialized via `startListening` | ||
| let listenerQueue | ||
|
|
||
| /** | ||
| * Run any dirty queries. See `calcQueries` for what constitutes a | ||
| * dirty query | ||
| */ | ||
| const runQueuedQueries = () => { | ||
| if (listenerQueue) { | ||
| listenerQueue.push(makeQueryJobs(calcQueries(false))) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Starts a background process that processes any dirty queries | ||
| * whenever one of the following occurs: | ||
| * | ||
| * 1. A node has changed (but only after the api call has finished | ||
| * running) | ||
| * 2. A component query (e.g by editing a React Component) has | ||
| * changed | ||
| * | ||
| * For what constitutes a dirty query, see `calcQueries` | ||
| */ | ||
| const startListening = queue => { | ||
| // We use a queue to process batches of queries so that they are | ||
| // processed consecutively | ||
| listenerQueue = new Queue((queryJobs, callback) => | ||
| queryQueue | ||
| .processBatch(queue, queryJobs) | ||
| .then(() => callback(null)) | ||
| .catch(callback) | ||
| ) | ||
|
|
||
| emitter.on(`API_RUNNING_QUEUE_EMPTY`, runQueuedQueries) | ||
| } | ||
|
|
||
| module.exports = { | ||
| runInitialQueries, | ||
| startListening, | ||
| runQueuedQueries, | ||
| queueQueryForPathname, | ||
| } | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is sooo much cleaner than what we had before! 👍