@stoplight/moleculer
Version:
Fast & powerful microservices framework for Node.JS
529 lines (489 loc) • 11.6 kB
JavaScript
/*
* moleculer
* Copyright (c) 2018 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/
;
/**
* Extendable errors class.
*
* Credits: https://github.com/bjyoungblood/es6-error/blob/master/src/index.js
*/
class ExtendableError extends Error {
constructor(message = "") {
super(message);
// extending Error is weird and does not propagate `message`
Object.defineProperty(this, "message", {
configurable: true,
enumerable: false,
value: message,
writable: true
});
Object.defineProperty(this, "name", {
configurable: true,
enumerable: false,
value: this.constructor.name,
writable: true
});
if (Object.prototype.hasOwnProperty.call(Error, "captureStackTrace")) {
Error.captureStackTrace(this, this.constructor);
return;
}
Object.defineProperty(this, "stack", {
configurable: true,
enumerable: false,
value: new Error(message).stack,
writable: true
});
}
}
/**
* Custom Moleculer Error class
*
* @class MoleculerError
* @extends {ExtendableError}
*/
class MoleculerError extends ExtendableError {
/**
* Creates an instance of MoleculerError.
*
* @param {String?} message
* @param {Number?} code
* @param {String?} type
* @param {any} data
*
* @memberof MoleculerError
*/
constructor(message, code, type, data) {
super(message);
this.code = code || 500;
this.type = type;
this.data = data;
this.retryable = false;
}
}
/**
* Custom Moleculer Error class for retryable errors.
*
* @class MoleculerRetryableError
* @extends {MoleculerError}
*/
class MoleculerRetryableError extends MoleculerError {
/**
* Creates an instance of MoleculerRetryableError.
*
* @param {String?} message
* @param {Number?} code
* @param {String?} type
* @param {any} data
*
* @memberof MoleculerRetryableError
*/
constructor(message, code, type, data) {
super(message);
this.code = code || 500;
this.type = type;
this.data = data;
this.retryable = true;
}
}
/**
* Moleculer Error class for Broker disconnections which is retryable.
*
* @class MoleculerServerError
* @extends {MoleculerRetryableError}
*/
class BrokerDisconnectedError extends MoleculerRetryableError {
constructor() {
super(
"The broker's transporter has disconnected. Please try again when a connection is reestablished.",
502,
"BAD_GATEWAY"
);
// Stack trace is hidden because it creates a lot of logs and, in this case, won't help users find the issue
this.stack = "";
}
}
/**
* Moleculer Error class for server error which is retryable.
*
* @class MoleculerServerError
* @extends {MoleculerRetryableError}
*/
class MoleculerServerError extends MoleculerRetryableError {}
/**
* Moleculer Error class for client errors which is not retryable.
*
* @class MoleculerClientError
* @extends {MoleculerError}
*/
class MoleculerClientError extends MoleculerError {
/**
* Creates an instance of MoleculerClientError.
*
* @param {String?} message
* @param {Number?} code
* @param {String?} type
* @param {any} data
*
* @memberof MoleculerClientError
*/
constructor(message, code, type, data) {
super(message, code || 400, type, data);
}
}
/**
* 'Service not found' Error message
*
* @class ServiceNotFoundError
* @extends {MoleculerRetryableError}
*/
class ServiceNotFoundError extends MoleculerRetryableError {
/**
* Creates an instance of ServiceNotFoundError.
*
* @param {Object} data
*
* @memberof ServiceNotFoundError
*/
constructor(data = {}) {
let msg;
if (data.nodeID && data.action)
msg = `Service '${data.action}' is not found on '${data.nodeID}' node.`;
else if (data.action) msg = `Service '${data.action}' is not found.`;
if (data.service && data.version)
msg = `Service '${data.version}.${data.service}' not found.`;
else if (data.service) msg = `Service '${data.service}' not found.`;
super(msg, 404, "SERVICE_NOT_FOUND", data);
}
}
/**
* 'Service not available' Error message
*
* @class ServiceNotAvailableError
* @extends {MoleculerRetryableError}
*/
class ServiceNotAvailableError extends MoleculerRetryableError {
/**
* Creates an instance of ServiceNotAvailableError.
*
* @param {Object} data
*
* @memberof ServiceNotAvailableError
*/
constructor(data) {
let msg;
if (data.nodeID)
msg = `Service '${data.action}' is not available on '${data.nodeID}' node.`;
else msg = `Service '${data.action}' is not available.`;
super(msg, 404, "SERVICE_NOT_AVAILABLE", data);
}
}
/**
* 'Request timed out' Error message. Retryable.
*
* @class RequestTimeoutError
* @extends {MoleculerRetryableError}
*/
class RequestTimeoutError extends MoleculerRetryableError {
/**
* Creates an instance of RequestTimeoutError.
*
* @param {Object} data
*
* @memberof RequestTimeoutError
*/
constructor(data) {
super(
`Request is timed out when call '${data.action}' action on '${data.nodeID}' node.`,
504,
"REQUEST_TIMEOUT",
data
);
}
}
/**
* 'Request skipped for timeout' Error message
*
* @class RequestSkippedError
* @extends {MoleculerError}
*/
class RequestSkippedError extends MoleculerError {
/**
* Creates an instance of RequestSkippedError.
*
* @param {Object} data
*
* @memberof RequestSkippedError
*/
constructor(data) {
super(
`Calling '${data.action}' is skipped because timeout reached on '${data.nodeID}' node.`,
514,
"REQUEST_SKIPPED",
data
);
this.retryable = false;
}
}
/**
* 'Request rejected' Error message. Retryable.
*
* @class RequestRejectedError
* @extends {MoleculerRetryableError}
*/
class RequestRejectedError extends MoleculerRetryableError {
/**
* Creates an instance of RequestRejectedError.
*
* @param {Object} data
*
* @memberof RequestRejectedError
*/
constructor(data) {
super(
`Request is rejected when call '${data.action}' action on '${data.nodeID}' node.`,
503,
"REQUEST_REJECTED",
data
);
}
}
/**
* 'Queue is full' error message. Retryable.
*
* @class QueueIsFullError
* @extends {MoleculerRetryableError}
*/
class QueueIsFullError extends MoleculerRetryableError {
/**
* Creates an instance of QueueIsFullError.
*
* @param {Object} data
*
* @memberof QueueIsFullError
*/
constructor(data) {
super(
`Queue is full. Request '${data.action}' action on '${data.nodeID}' node is rejected.`,
429,
"QUEUE_FULL",
data
);
}
}
/**
* 'Parameters of action call validation error
*
* @class ValidationError
* @extends {MoleculerClientError}
*/
class ValidationError extends MoleculerClientError {
/**
* Creates an instance of ValidationError.
*
* @param {String} message
* @param {String} type
* @param {any} data
*
* @memberof ValidationError
*/
constructor(message, type, data) {
super(message, 422, type || "VALIDATION_ERROR", data);
}
}
/**
* 'Max request call level!' Error message
*
* @class MaxCallLevelError
* @extends {MoleculerError}
*/
class MaxCallLevelError extends MoleculerError {
/**
* Creates an instance of MaxCallLevelError.
*
* @param {Object} data
*
* @memberof MaxCallLevelError
*/
constructor(data) {
super(
`Request level is reached the limit (${data.level}) on '${data.nodeID}' node.`,
500,
"MAX_CALL_LEVEL",
data
);
this.retryable = false;
}
}
/**
* Custom Moleculer Error class for Service schema errors
*
* @class ServiceSchemaError
* @extends {Error}
*/
class ServiceSchemaError extends MoleculerError {
/**
* Creates an instance of ServiceSchemaError.
*
* @param {String} msg
* @param {Object} data
* @memberof ServiceSchemaError
*/
constructor(msg, data) {
super(msg, 500, "SERVICE_SCHEMA_ERROR", data);
}
}
/**
* Custom Moleculer Error class for broker option errors
*
* @class BrokerOptionsError
* @extends {Error}
*/
class BrokerOptionsError extends MoleculerError {
/**
* Creates an instance of BrokerOptionsError.
*
* @param {String} msg
* @param {Object} data
* @memberof BrokerOptionsError
*/
constructor(msg, data) {
super(msg, 500, "BROKER_OPTIONS_ERROR", data);
}
}
/**
* Custom Moleculer Error class for Graceful stopping
*
* @class GracefulStopTimeoutError
* @extends {Error}
*/
class GracefulStopTimeoutError extends MoleculerError {
/**
* Creates an instance of GracefulStopTimeoutError.
*
* @param {Object?} data
* @memberof GracefulStopTimeoutError
*/
constructor(data) {
if (data && data.service) {
super(
`Unable to stop '${data.service.name}' service gracefully.`,
500,
"GRACEFUL_STOP_TIMEOUT",
data && data.service
? {
name: data.service.name,
version: data.service.version
}
: null
);
} else {
super("Unable to stop ServiceBroker gracefully.", 500, "GRACEFUL_STOP_TIMEOUT");
}
}
}
/**
* Protocol version is mismatch
*
* @class ProtocolVersionMismatchError
* @extends {Error}
*/
class ProtocolVersionMismatchError extends MoleculerError {
/**
* Creates an instance of ProtocolVersionMismatchError.
*
* @param {Object} data
*
* @memberof ProtocolVersionMismatchError
*/
constructor(data) {
super("Protocol version mismatch.", 500, "PROTOCOL_VERSION_MISMATCH", data);
}
}
/**
* Invalid packet format error
*
* @class InvalidPacketDataError
* @extends {Error}
*/
class InvalidPacketDataError extends MoleculerError {
/**
* Creates an instance of InvalidPacketDataError.
*
* @param {Object} data
*
* @memberof InvalidPacketDataError
*/
constructor(data) {
super("Invalid packet data.", 500, "INVALID_PACKET_DATA", data);
}
}
/**
* Recreate an error from a transferred payload `err`
*
* @param {Error} err
* @returns {MoleculerError}
*/
function recreateError(err) {
const Class = module.exports[err.name];
if (Class) {
switch (err.name) {
case "MoleculerError":
return new Class(err.message, err.code, err.type, err.data);
case "MoleculerRetryableError":
return new Class(err.message, err.code, err.type, err.data);
case "MoleculerServerError":
return new Class(err.message, err.code, err.type, err.data);
case "MoleculerClientError":
return new Class(err.message, err.code, err.type, err.data);
case "ValidationError":
return new Class(err.message, err.type, err.data);
case "ServiceNotFoundError":
return new Class(err.data);
case "ServiceNotAvailableError":
return new Class(err.data);
case "RequestTimeoutError":
return new Class(err.data);
case "RequestSkippedError":
return new Class(err.data);
case "RequestRejectedError":
return new Class(err.data);
case "QueueIsFullError":
return new Class(err.data);
case "MaxCallLevelError":
return new Class(err.data);
case "GracefulStopTimeoutError":
return new Class(err.data);
case "ProtocolVersionMismatchError":
return new Class(err.data);
case "InvalidPacketDataError":
return new Class(err.data);
case "ServiceSchemaError":
case "BrokerOptionsError":
return new Class(err.message, err.data);
}
}
}
module.exports = {
ExtendableError,
MoleculerError,
MoleculerRetryableError,
MoleculerServerError,
MoleculerClientError,
ServiceNotFoundError,
ServiceNotAvailableError,
ValidationError,
RequestTimeoutError,
RequestSkippedError,
RequestRejectedError,
QueueIsFullError,
MaxCallLevelError,
ServiceSchemaError,
BrokerOptionsError,
GracefulStopTimeoutError,
ProtocolVersionMismatchError,
InvalidPacketDataError,
BrokerDisconnectedError,
recreateError
};