Skip to content

Commit

Permalink
fix: fixes to errors and adding un-recoverable error handlers
Browse files Browse the repository at this point in the history
Un-recoverable errors include `ErrorBinUncaughtException`, `ErrorBinUnhandledRejection` and `ErrorBinAsynchronousDeadlock`.

#414
  • Loading branch information
tegefaulkes committed Sep 21, 2022
1 parent 03896d1 commit ed47010
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 60 deletions.
39 changes: 27 additions & 12 deletions src/bin/errors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
import ErrorPolykey from '../ErrorPolykey';
import sysexits from '../utils/sysexits';

class ErrorCLI<T> extends ErrorPolykey<T> {}
class ErrorBin<T> extends ErrorPolykey<T> {}

class ErrorBinUncaughtException<T> extends ErrorBin<T> {
static description = '';
exitCode = sysexits.SOFTWARE;
}

class ErrorBinUnhandledRejection<T> extends ErrorBin<T> {
static description = '';
exitCode = sysexits.SOFTWARE;
}

class ErrorBinAsynchronousDeadlock<T> extends ErrorBin<T> {
static description =
'PolykeyAgent process exited unexpectedly, likely due to promise deadlock';
exitCode = sysexits.SOFTWARE;
}

class ErrorCLI<T> extends ErrorBin<T> {}

class ErrorCLINodePath<T> extends ErrorCLI<T> {
static description = 'Cannot derive default node path from unknown platform';
Expand Down Expand Up @@ -49,23 +67,21 @@ class ErrorCLIPolykeyAgentProcess<T> extends ErrorCLI<T> {
exitCode = sysexits.OSERR;
}

class ErrorCLIPolykeyAsynchronousDeadlock<T> extends ErrorCLI<T> {
static description =
'PolykeyAgent process exited unexpectedly, likely due to promise deadlock';
exitCode = sysexits.SOFTWARE;
}

class ErrorNodeFindFailed<T> extends ErrorCLI<T> {
class ErrorCLINodeFindFailed<T> extends ErrorCLI<T> {
static description = 'Failed to find the node in the DHT';
exitCode = 1;
}

class ErrorNodePingFailed<T> extends ErrorCLI<T> {
class ErrorCLINodePingFailed<T> extends ErrorCLI<T> {
static description = 'Node was not online or not found.';
exitCode = 1;
}

export {
ErrorBin,
ErrorBinUncaughtException,
ErrorBinUnhandledRejection,
ErrorBinAsynchronousDeadlock,
ErrorCLI,
ErrorCLINodePath,
ErrorCLIClientOptions,
Expand All @@ -76,7 +92,6 @@ export {
ErrorCLIFileRead,
ErrorCLIPolykeyAgentStatus,
ErrorCLIPolykeyAgentProcess,
ErrorCLIPolykeyAsynchronousDeadlock,
ErrorNodeFindFailed,
ErrorNodePingFailed,
ErrorCLINodeFindFailed,
ErrorCLINodePingFailed,
};
2 changes: 1 addition & 1 deletion src/bin/nodes/CommandFind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class CommandFind extends CommandPolykey {
);
// Like ping it should error when failing to find node for automation reasons.
if (!result.success) {
throw new binErrors.ErrorNodeFindFailed(result.message);
throw new binErrors.ErrorCLINodeFindFailed(result.message);
}
} finally {
if (pkClient! != null) await pkClient.stop();
Expand Down
4 changes: 2 additions & 2 deletions src/bin/nodes/CommandPing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class CommandPing extends CommandPolykey {
);
} catch (err) {
if (err.cause instanceof nodesErrors.ErrorNodeGraphNodeIdNotFound) {
error = new binErrors.ErrorNodePingFailed(
error = new binErrors.ErrorCLINodePingFailed(
`Failed to resolve node ID ${nodesUtils.encodeNodeId(
nodeId,
)} to an address.`,
Expand All @@ -69,7 +69,7 @@ class CommandPing extends CommandPolykey {
const status = { success: false, message: '' };
status.success = statusMessage ? statusMessage.getSuccess() : false;
if (!status.success && !error) {
error = new binErrors.ErrorNodePingFailed('No response received');
error = new binErrors.ErrorCLINodePingFailed('No response received');
}
if (status.success) status.message = 'Node is Active.';
else status.message = error.message;
Expand Down
94 changes: 55 additions & 39 deletions src/bin/utils/ExitHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import process from 'process';
import * as binUtils from './utils';
import ErrorPolykey from '../../ErrorPolykey';
import * as CLIErrors from '../errors';
import * as binErrors from '../errors';

class ExitHandlers {
/**
Expand All @@ -11,38 +11,6 @@ class ExitHandlers {
public handlers: Array<(signal?: NodeJS.Signals) => Promise<void>>;
protected _exiting: boolean = false;
protected _errFormat: 'json' | 'error';
/**
* Handles synchronous and asynchronous exceptions
* This prints out appropriate error message on STDERR
* It sets the exit code according to the error
* 255 is set for unknown errors
*/
protected errorHandler = async (e: Error) => {
if (this._exiting) {
return;
}
this._exiting = true;
if (e instanceof ErrorPolykey) {
process.stderr.write(
binUtils.outputFormatter({
type: this._errFormat,
data: e,
}),
);
process.exitCode = e.exitCode;
} else {
// Unknown error, this should not happen
process.stderr.write(
binUtils.outputFormatter({
type: this._errFormat,
data: e,
}),
);
process.exitCode = 255;
}
// Fail fast pattern
process.exit();
};
/**
* Handles termination signals
* This is idempotent
Expand Down Expand Up @@ -84,10 +52,55 @@ class ExitHandlers {
process.kill(process.pid, signal);
}
};

/**
* Handles asynchronous exceptions
* This prints out appropriate error message on STDERR
* It sets the exit code to SOFTWARE
*/
protected unhandledRejectionHandler = async (e: Error) => {
if (this._exiting) {
return;
}
this._exiting = true;
const error = new binErrors.ErrorBinUnhandledRejection(undefined, {
cause: e,
});
process.stderr.write(
binUtils.outputFormatter({
type: this._errFormat,
data: e,
}),
);
process.exitCode = error.exitCode;
// Fail fast pattern
process.exit();
};
/**
* Handles synchronous exceptions
* This prints out appropriate error message on STDERR
* It sets the exit code to SOFTWARE
*/
protected uncaughtExceptionHandler = async (e: Error) => {
if (this._exiting) {
return;
}
this._exiting = true;
const error = new binErrors.ErrorBinUncaughtException(undefined, {
cause: e,
});
process.stderr.write(
binUtils.outputFormatter({
type: this._errFormat,
data: e,
}),
);
process.exitCode = error.exitCode;
// Fail fast pattern
process.exit();
};
protected deadlockHandler = async () => {
if (process.exitCode == null) {
const e = new CLIErrors.ErrorCLIPolykeyAsynchronousDeadlock();
const e = new binErrors.ErrorBinAsynchronousDeadlock();
process.stderr.write(
binUtils.outputFormatter({
type: this._errFormat,
Expand Down Expand Up @@ -122,8 +135,8 @@ class ExitHandlers {
process.on('SIGQUIT', this.signalHandler);
process.on('SIGHUP', this.signalHandler);
// Both synchronous and asynchronous errors are handled
process.once('unhandledRejection', this.errorHandler);
process.once('uncaughtException', this.errorHandler);
process.once('unhandledRejection', this.unhandledRejectionHandler);
process.once('uncaughtException', this.uncaughtExceptionHandler);
process.once('beforeExit', this.deadlockHandler);
}

Expand All @@ -132,8 +145,11 @@ class ExitHandlers {
process.removeListener('SIGTERM', this.signalHandler);
process.removeListener('SIGQUIT', this.signalHandler);
process.removeListener('SIGHUP', this.signalHandler);
process.removeListener('unhandledRejection', this.errorHandler);
process.removeListener('uncaughtException', this.errorHandler);
process.removeListener(
'unhandledRejection',
this.unhandledRejectionHandler,
);
process.removeListener('uncaughtException', this.uncaughtExceptionHandler);
process.removeListener('beforeExit', this.deadlockHandler);
}

Expand Down
6 changes: 0 additions & 6 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ class ErrorPolykeyClientDestroyed<T> extends ErrorPolykey<T> {
exitCode = sysexits.USAGE;
}

class ErrorInvalidId<T> extends ErrorPolykey<T> {}

class ErrorInvalidConfigEnvironment<T> extends ErrorPolykey<T> {}

export {
sysexits,
ErrorPolykey,
Expand All @@ -56,8 +52,6 @@ export {
ErrorPolykeyClientRunning,
ErrorPolykeyClientNotRunning,
ErrorPolykeyClientDestroyed,
ErrorInvalidId,
ErrorInvalidConfigEnvironment,
};

/**
Expand Down

0 comments on commit ed47010

Please sign in to comment.