0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-01-06 22:40:26 -05:00

refactor: 🔨 don't crash main thread when the database file is corrupted

Add a lock for LocalData instance and throw error message while user trying modify package list
This commit is contained in:
Meeeeow 2017-08-20 00:27:18 +08:00 committed by Juan Picado @jotadeveloper
parent 5d73dcaf89
commit 552527c085
No known key found for this signature in database
GPG key ID: 18AC54485952D158
2 changed files with 36 additions and 12 deletions

View file

@ -21,15 +21,13 @@ const logger = require('../../logger');
try {
dbFile = fs.readFileSync(this.path, 'utf8');
} catch (err) {
if (err.code === 'ENOENT') { // Only recreate if file not found to prevent data loss
this.data = {list: []};
} else {
if (err.code !== 'ENOENT') { // Only recreate if file not found to prevent data loss
logger.logger.error(
'Failed to read package database file, please check the error printed below and fix it manually:\n',
'Failed to read package database file, please check the error printed below:\n',
`File Path: ${this.path}\n\n`,
err
);
throw new Error('Package database file unreachable');
this.locked = true; // Prevent any write action, wait admin to check what happened during startup
}
}
@ -37,33 +35,39 @@ const logger = require('../../logger');
try {
this.data = JSON.parse(dbFile);
} catch(err) {
logger.logger.error(err);
throw new Error(`Package database file corrupted (invalid JSON), please fix it manually.\nFile Path: ${this.path}`);
logger.logger.error(`Package database file corrupted (invalid JSON), please check the error printed below.\nFile Path: ${this.path}`, err);
this.locked = true;
}
}
if (!this.data) {
this.data = {list: []};
}
}
/**
* Add a new element.
* @param {*} name
* @return {Error|*}
*/
add(name) {
if (this.data.list.indexOf(name) === -1) {
this.data.list.push(name);
this.sync();
return this.sync();
}
}
/**
* Remove an element from the database.
* @param {*} name
* @return {Error|*}
*/
remove(name) {
const i = this.data.list.indexOf(name);
if (i !== -1) {
this.data.list.splice(i, 1);
}
this.sync();
return this.sync();
}
/**
@ -76,8 +80,14 @@ const logger = require('../../logger');
/**
* Syncronize {create} database whether does not exist.
* @return {Error|*}
*/
sync() {
if (this.locked) {
logger.logger.error('Database is locked, please check error message printed during startup to prevent data loss.');
return new Error('Verdaccio database is locked, please contact your administrator to checkout logs during verdaccio startup.');
}
// Uses sync to prevent ugly race condition
try {
require('mkdirp').sync(Path.dirname(this.path));
@ -85,7 +95,11 @@ const logger = require('../../logger');
// perhaps a logger instance?
/* eslint no-empty:off */
}
fs.writeFileSync(this.path, JSON.stringify(this.data));
try {
fs.writeFileSync(this.path, JSON.stringify(this.data));
} catch (err) {
return err;
}
}
}

View file

@ -119,6 +119,12 @@ class LocalStorage {
}
this._normalizePackage(data);
let removeFailed = this.localList.remove(name);
if (removeFailed) {
// This will happen when database is locked
return callback(this.utils.ErrorCode.get422(removeFailed.message));
}
storage.unlink(pkgFileName, function(err) {
if (err) {
return callback(err);
@ -145,7 +151,6 @@ class LocalStorage {
});
});
});
this.localList.remove(name);
}
/**
@ -296,7 +301,12 @@ class LocalStorage {
data.versions[version] = metadata;
this.utils.tag_version(data, version, tag);
this.localList.add(name);
let addFailed = this.localList.add(name);
if (addFailed) {
return cb(this.utils.ErrorCode.get422(addFailed.message));
}
cb();
}, callback);
}