Skip to content

Commit

Permalink
feat: lock file
Browse files Browse the repository at this point in the history
This introduces a lock file for xud that is created in the xud data
directory any time xud starts up. Anytime a lock file already exists,
an error message is logged and xud exits. This prevents multiple
xud processes from trying to use the same node key or directory at the
same time.

The lock files are unique to each network, so running multiple processes
with different networks (e.g. simnet and mainnet) is allowed. They are
deleted when xud shuts down.

Closes #1989.
  • Loading branch information
sangaman committed Dec 2, 2020
1 parent 7ecdd7e commit aa69874
Showing 1 changed file with 24 additions and 4 deletions.
28 changes: 24 additions & 4 deletions lib/Xud.ts
Expand Up @@ -35,9 +35,9 @@ class Xud extends EventEmitter {
public service!: Service;
private logger!: Logger;
private config: Config;
private db!: DB;
private pool!: Pool;
private orderBook!: OrderBook;
private db?: DB;
private pool?: Pool;
private orderBook?: OrderBook;
private rpcServer?: GrpcServer;
private httpServer?: HttpServer;
private grpcAPIProxy?: GrpcWebProxyServer;
Expand All @@ -46,6 +46,7 @@ class Xud extends EventEmitter {
private swapClientManager?: SwapClientManager;
private unitConverter?: UnitConverter;
private simnetChannels$?: Subscription;
private lockFilePath?: string;

/**
* Create an Exchange Union daemon.
Expand Down Expand Up @@ -88,6 +89,21 @@ class Xud extends EventEmitter {
}

try {
// create a lock file to prevent multiple xud instances from trying to run
// with the same node key and/or database
const lockFilePath = path.join(this.config.xudir, `${this.config.network}.lock`);
try {
await (await fs.open(lockFilePath, 'wx')).close();
this.lockFilePath = lockFilePath;
} catch (err) {
if (err.code === 'EEXIST') {
this.logger.error(`A lock file exists at ${lockFilePath}. Another xud process is running or a previous process exited ungracefully.`);
return;
} else {
throw err;
}
}

if (!this.config.rpc.disable) {
// start rpc server first, it will respond with UNAVAILABLE error
// indicating xud is starting until xud finishes initializing
Expand Down Expand Up @@ -296,6 +312,10 @@ class Xud extends EventEmitter {
// TODO: ensure we are not in the middle of executing any trades
const closePromises: Promise<void>[] = [];

if (this.lockFilePath) {
closePromises.push(fs.unlink(this.lockFilePath).catch(this.logger.error));
}

this.simnetChannels$?.unsubscribe();

if (this.swapClientManager) {
Expand All @@ -318,7 +338,7 @@ class Xud extends EventEmitter {
}
await Promise.all(closePromises);

await this.db.close();
await this.db?.close();
this.logger.info('XUD shutdown gracefully');

this.emit('shutdown');
Expand Down

0 comments on commit aa69874

Please sign in to comment.