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:
parent
5d73dcaf89
commit
552527c085
2 changed files with 36 additions and 12 deletions
|
@ -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 */
|
||||
}
|
||||
try {
|
||||
fs.writeFileSync(this.path, JSON.stringify(this.data));
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue