Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/cache-provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const NodeCache = require('node-cache')
let cache = null

exports.start = function (done) {
if (cache) return done()

cache = new NodeCache()
}

exports.instance = function () {
return cache
}
5 changes: 5 additions & 0 deletions lib/create-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const { routeResolvedFile } = require('./utils')
const ResourceMapper = require('./resource-mapper')
const aclCheck = require('@solid/acl-check')
const { version } = require('../package.json')
const cacheProvider = require('./cache-provider') // alain

const corsSettings = cors({
methods: [
Expand Down Expand Up @@ -60,6 +61,10 @@ function createApp (argv = {}) {

const app = express()

cacheProvider.start(function (err) { // alain initCacheProvider
if (err) console.error(err)
})

initAppLocals(app, argv, ldp)
initHeaders(app)
initViews(app, configPath)
Expand Down
69 changes: 54 additions & 15 deletions lib/lock.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,72 @@
/* eslint-disable no-async-promise-executor */

const { lock } = require('proper-lockfile')
const cache = require('./cache-provider')
const { EventEmitter } = require('events')

const staleSeconds = 30

// Obtains a lock on the path, and maintains it until the callback finishes
/**
* Obtains a lock on the path, and maintains it until the callback finishes
* @param {*} path
* @param {*} options
* @param {*} callback
*/
function withLock (path, options = {}, callback = options) {
return new Promise(async (resolve, reject) => {
let releaseLock, result
let result
try {
// Obtain the lock
releaseLock = await lock(path, {
retries: 10,
update: 1000,
stale: staleSeconds * 1000,
realpath: !!options.mustExist,
onCompromised: () =>
reject(new Error(`The file at ${path} was not updated within ${staleSeconds}s.`))
})
// Hold on to the lock until the callback's returned promise resolves
lock().acquire(path) // boolean // kept unlimited time
result = await callback()
} catch (error) {
reject(error)
// Ensure the lock is always released
} finally {
await releaseLock()
// allways releaseLock()
lock().release(path)
}
resolve(result)
})
}

/**
* https://medium.com/trabe/synchronize-cache-updates-in-node-js-with-a-mutex-d5b395457138
* There are some npm libraries that implement some kind of mutex support (lock, mutex, async-lock) but none of them feel as simple and elegant as Valeri’s code.
* His solution (pasted below with original comments):
*
* Uses a boolean to keep the locked/unlocked state of the mutex.
* Uses promises to wait for the release of the lock.
* Relies on an event emitter to notify the code that is waiting when the lock is released.
*/
const lock = () => {
const ee = new EventEmitter()
ee.setMaxListeners(0)

return {
acquire: key =>
new Promise(resolve => {
if (!cache.instance().get(key)) {
cache.instance().set(key, true)
return resolve()
}

const tryAcquire = value => {
if (!cache.instance().get(key)) {
cache.instance().set(key, true)
ee.removeListener(key, tryAcquire)
return resolve(value)
}
}

ee.on(key, tryAcquire)
}),

// If we pass a value, on release this value
// will be propagated to all the code that's waiting for
// the lock to release
release: (key, value) => {
cache.instance().del(key)
setImmediate(() => ee.emit(key, value))
}
}
}

module.exports = withLock
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"mime-types": "^2.1.27",
"mkdir-recursive": "^0.4.0",
"negotiator": "^0.6.2",
"node-cache": "^5.1.2",
"node-fetch": "^2.6.0",
"node-forge": "^0.9.1",
"nodemailer": "^6.4.11",
Expand Down