When I use Google Cloud services in NodeJS I have to access resources like Buckets (in Storage) and the first time I call them, I have to check if they exists, if not, create them.
Well, if multiple resources access the same bucket at the start of the application, they will try to create it at same time.
To prevent the stampede I have to use something like this:
getStorage(id) {
return new Promise((resolve, reject) => {
// Exists storage?
if(id in this.storage) {
let storage = this.storage[id];
// Storage is ready, deliver
if(storage.ready) {
return resolve(storage);
}
// Not ready, wait until storage is ready
let wait;
let start = +Date.now();
wait = setInterval(() => {
// Storage is now ready
if(storage.ready) {
clearInterval(wait);
return resolve(storage);
}
// Timeout in 15 seconds
if(+Date.now() - start > 15*1000) {
clearInterval(wait);
return reject(new Error('timeout while waiting storage creation'));
}
}, 10);
return;
}
// Start storage creation
let storage = new Storage(id);
this.storage[id] = storage;
storage
.create()
.then(resolve, reject);
});
}
Is anything in lodash, underscore or async that helps with this scenario? A instance stampede scenario.
Semaphores will be useful?
In async style it could be something like this:
getStorage(id) {
return new Promise((resolve, reject) => {
// already found
if(id in this.storage) {
resolve(this.storage[id]);
return;
}
// prevent stampede
// async.stampede( UNIQUE_ID, CREATE, RESULT )
// - CREATE will be called once for UNIQUE_ID
async.stampede(id, (end) => {
let storage = new Storage(id);
storage
.create()
.then(
() => end(null, storage),
(err) => end(err)
);
}, (err, result) => {
if(err) reject(err);
else {
this.storage[id] = storage;
resolve(result);
}
});
});
}
In lodash it can be something like "once" but with promises.