Skip to content

Commit

Permalink
fix(gatsby): [loki] sync db autosaves (#10212)
Browse files Browse the repository at this point in the history
This PR orchestrates the saving of db state for both loki and redux into one place. Previously, loki would use its `autosave` feature and save to disk every 1000ms. Whereas now, it uses the same style as `gatsby/redux` where a debounced save is triggered for each new event. 

Note that both database save asynchronously (redux's write to disk is async) so this isn't a perfect "Stop the world" synchronized save. However it's better than it was before.
  • Loading branch information
Moocar authored and pieh committed Dec 7, 2018
1 parent a51a752 commit 1c0d051
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 25 deletions.
1 change: 1 addition & 0 deletions packages/gatsby/src/bootstrap/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const getConfigFile = require(`./get-config-file`)
const tracer = require(`opentracing`).globalTracer()
const preferDefault = require(`./prefer-default`)
const nodeTracking = require(`../db/node-tracking`)
require(`../db`).startAutosave()

// Show stack trace on unhandled promises.
process.on(`unhandledRejection`, (reason, p) => {
Expand Down
50 changes: 50 additions & 0 deletions packages/gatsby/src/db/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const _ = require(`lodash`)
const redux = require(`../redux`)
const { emitter } = redux

// Even if we are using loki, we still include redux in the list of
// dbs since it still has pages, config, etc.
const dbs = [redux]
if (process.env.GATSBY_DB_NODES === `loki`) {
dbs.push(require(`./loki`))
}

// calls `saveState()` on all DBs
function saveState() {
for (const db of dbs) {
db.saveState()
}
}
const saveStateDebounced = _.debounce(saveState, 1000)

/**
* Sets up listeners so that once bootstrap has finished, all
* databases save their state to disk. If we're in `develop` mode,
* then any new event triggers a debounced save as well.
*/
function startAutosave() {
// During development, once bootstrap is finished, persist state on changes.
let bootstrapFinished = false
if (process.env.gatsby_executing_command === `develop`) {
emitter.on(`BOOTSTRAP_FINISHED`, () => {
bootstrapFinished = true
saveState()
})
emitter.on(`*`, () => {
if (bootstrapFinished) {
saveStateDebounced()
}
})
}

// During builds, persist state once bootstrap has finished.
if (process.env.gatsby_executing_command === `build`) {
emitter.on(`BOOTSTRAP_FINISHED`, () => {
saveState()
})
}
}

module.exports = {
startAutosave,
}
21 changes: 19 additions & 2 deletions packages/gatsby/src/db/loki/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ function startFileDb(saveFile) {
resolve()
}
},
autosave: true,
autosaveInterval: 1000,
}
db = new loki(saveFile, dbOptions)
})
Expand Down Expand Up @@ -109,6 +107,24 @@ async function start({ saveFile } = {}) {
ensureNodeCollections(db)
}

// Saves the database to disk and returns a promise that will be
// resolved once the save has finished
function saveState() {
return new Promise((resolve, reject) => {
if (db) {
db.saveDatabase(err => {
if (err) {
console.log(`error saving loki DB`)
console.log(err)
reject(err)
} else {
resolve()
}
})
}
})
}

/**
* Returns a reference to the database. If undefined, the db has not been
* initalized yet. Call `start()`
Expand All @@ -123,4 +139,5 @@ module.exports = {
start,
getDb,
colls,
saveState,
}
27 changes: 4 additions & 23 deletions packages/gatsby/src/redux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ const store = Redux.createStore(
)

// Persist state.
const saveState = state => {
function saveState() {
const state = store.getState()
const pickedState = _.pick(state, [
`nodes`,
`status`,
Expand All @@ -85,34 +86,14 @@ const saveState = state => {
() => {}
)
}
const saveStateDebounced = _.debounce(saveState, 1000)

exports.saveState = saveState

store.subscribe(() => {
const lastAction = store.getState().lastAction
emitter.emit(lastAction.type, lastAction)
})

// During development, once bootstrap is finished, persist state on changes.
let bootstrapFinished = false
if (process.env.gatsby_executing_command === `develop`) {
emitter.on(`BOOTSTRAP_FINISHED`, () => {
bootstrapFinished = true
saveState(store.getState())
})
emitter.on(`*`, () => {
if (bootstrapFinished) {
saveStateDebounced(store.getState())
}
})
}

// During builds, persist state once bootstrap has finished.
if (process.env.gatsby_executing_command === `build`) {
emitter.on(`BOOTSTRAP_FINISHED`, () => {
saveState(store.getState())
})
}

/** Event emitter */
exports.emitter = emitter

Expand Down

0 comments on commit 1c0d051

Please sign in to comment.