@stoplight/moleculer
Version:
Fast & powerful microservices framework for Node.JS
99 lines (84 loc) • 2.68 kB
JavaScript
/*
* moleculer
* Copyright (c) 2018 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/
;
const { MoleculerError } = require("../errors");
const { METRIC } = require("../metrics");
const { isFunction, isString } = require("../utils");
module.exports = function FallbackMiddleware(broker) {
function handleContextFallback(ctx, err) {
broker.logger.warn(
`The '${ctx.action.name}' request is failed. Return fallback response.`,
{ requestID: ctx.requestID, err: err.message }
);
broker.metrics.increment(METRIC.MOLECULER_REQUEST_FALLBACK_TOTAL, {
action: ctx.action.name
});
ctx.fallbackResult = true;
if (isFunction(ctx.options.fallbackResponse)) return ctx.options.fallbackResponse(ctx, err);
else return Promise.resolve(ctx.options.fallbackResponse);
}
function wrapFallbackMiddleware(handler, action) {
return function fallbackMiddleware(ctx) {
// Call the handler
return handler(ctx).catch(err => {
// Handle fallback response from calling options
if (ctx.options.fallbackResponse) {
return handleContextFallback(ctx, err);
}
// Handle fallback from Action Definition (only locally)
if (action.fallback && action.service) {
const svc = action.service;
const fallback = isString(action.fallback)
? svc[action.fallback]
: action.fallback;
if (!isFunction(fallback)) {
/* istanbul ignore next */
throw new MoleculerError(
`The 'fallback' of '${action.name}' action is not a Function or valid method name: ${action.fallback}`
);
}
svc.logger.warn(
`The '${ctx.action.name}' request is failed. Return fallback response.`,
{ requestID: ctx.requestID, err: err.message }
);
broker.metrics.increment(METRIC.MOLECULER_REQUEST_FALLBACK_TOTAL, {
service: svc.fullName,
action: action.name
});
ctx.fallbackResult = true;
return fallback.call(svc, ctx, err);
}
return Promise.reject(err);
});
}.bind(this);
}
return {
name: "Fallback",
created(broker) {
if (broker.isMetricsEnabled()) {
broker.metrics.register({
name: METRIC.MOLECULER_REQUEST_FALLBACK_TOTAL,
type: METRIC.TYPE_COUNTER,
labelNames: ["service", "action"],
description: "Number of fallbacked requests",
rate: true
});
}
},
localAction: wrapFallbackMiddleware,
remoteAction: wrapFallbackMiddleware
/*call(next) {
return (actionName, params, opts) => {
return next(actionName, params, opts).catch(err => {
if (opts.fallbackResponse) {
return handleContextFallback(null, err);
}
throw err;
});
};
},*/
};
};