Skip to content

Commit

Permalink
Error handler doesn't catch the errors in localEvent hook. Closes #991
Browse files Browse the repository at this point in the history
  • Loading branch information
icebob committed Jan 14, 2023
1 parent 096d0af commit 317e68b
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 63 deletions.
41 changes: 18 additions & 23 deletions src/middlewares/error-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,33 +44,28 @@ function wrapActionErrorHandler(handler) {
function wrapEventErrorHandler(handler) {
return function errorHandlerMiddleware(ctx) {
// Call the handler
return handler(ctx)
.catch(err => {
if (!(err instanceof Error)) err = new MoleculerError(err, 500);
return handler(ctx).catch(err => {
if (!(err instanceof Error)) err = new MoleculerError(err, 500);

this.logger.debug(
`Error occured in the '${ctx.event.name}' event handler in the '${ctx.service.fullName}' service.`,
{ requestID: ctx.requestID },
err
);
this.logger.debug(
`Error occured in the '${ctx.event.name}' event handler in the '${ctx.service.fullName}' service.`,
{ requestID: ctx.requestID },
err
);

Object.defineProperty(err, "ctx", {
value: ctx,
writable: true,
enumerable: false
});
Object.defineProperty(err, "ctx", {
value: ctx,
writable: true,
enumerable: false
});

// Call global errorHandler
return ctx.broker.errorHandler(err, {
ctx,
service: ctx.service,
event: ctx.event
});
})
.catch(err => {
// No global error Handler, or thrown further, so we handle it because it's an event handler.
ctx.broker.logger.error(err);
// Call global errorHandler
return ctx.broker.errorHandler(err, {
ctx,
service: ctx.service,
event: ctx.event
});
});
}.bind(this);
}

Expand Down
2 changes: 1 addition & 1 deletion src/registry/action-catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class ActionCatalog {
onlyAvailable = false,
skipInternal = false,
withEndpoints = false
}) {
} = {}) {
let res = [];

this.actions.forEach((list, key) => {
Expand Down
4 changes: 2 additions & 2 deletions src/registry/event-catalog.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* moleculer
* Copyright (c) 2018 MoleculerJS (https://github.com/moleculerjs/moleculer)
* Copyright (c) 2023 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/

Expand Down Expand Up @@ -246,7 +246,7 @@ class EventCatalog {
onlyAvailable = false,
skipInternal = false,
withEndpoints = false
}) {
} = {}) {
let res = [];

this.events.forEach(list => {
Expand Down
2 changes: 1 addition & 1 deletion src/registry/node-catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ class NodeCatalog {
* @returns
* @memberof NodeCatalog
*/
list({ onlyAvailable = false, withServices = false }) {
list({ onlyAvailable = false, withServices = false } = {}) {
let res = [];
this.nodes.forEach(node => {
if (onlyAvailable && !node.available) return;
Expand Down
2 changes: 1 addition & 1 deletion src/registry/service-catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class ServiceCatalog {
withActions = false,
withEvents = false,
grouping = false
}) {
} = {}) {
let res = [];
this.services.forEach(service => {
if (skipInternal && /^\$/.test(service.name)) return;
Expand Down
19 changes: 15 additions & 4 deletions src/service-broker.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* moleculer
* Copyright (c) 2020 MoleculerJS (https://github.com/moleculerjs/moleculer)
* Copyright (c) 2023 MoleculerJS (https://github.com/moleculerjs/moleculer)
* MIT Licensed
*/

Expand Down Expand Up @@ -1425,7 +1425,12 @@ class ServiceBroker {
if (ep.id === this.nodeID) {
// Local service, call handler
const newCtx = ctx.copy(ep);
promises.push(this.registry.events.callEventHandler(newCtx));
promises.push(
this.registry.events.callEventHandler(newCtx).catch(err => {
// Catch and log the error because it's a local event handler, not throwing further.
this.logger.error(err);
})
);
} else {
// Remote service
const e = groupedEP[ep.id];
Expand Down Expand Up @@ -1564,7 +1569,10 @@ class ServiceBroker {
ctx.eventType = "broadcastLocal";
ctx.eventGroups = opts.groups;

return this.emitLocalServices(ctx);
return this.emitLocalServices(ctx).catch(err => {
// Catch and log the error because it's a local event handler, not throwing further.
this.logger.error(err);
});
}

/**
Expand Down Expand Up @@ -1698,7 +1706,10 @@ class ServiceBroker {
* @memberof ServiceBroker
*/
emitLocalServices(ctx) {
return this.registry.events.emitLocalServices(ctx);
return this.registry.events.emitLocalServices(ctx).catch(err => {
// Catch and log the error because it's a local event handler, not throwing further.
this.logger.error(err);
});
}

/**
Expand Down
33 changes: 6 additions & 27 deletions test/unit/middlewares/error-handler.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ describe("Test ErrorHandlerMiddleware", () => {
const ctx = Context.create(broker, eventEndpoint);

return newHandler(ctx)
.catch(protectReject)
.catch(err => {
expect(err).toBe(error);
})
.then(() => {
expect(error.ctx).toBe(ctx);
expect(broker.errorHandler).toBeCalledTimes(1);
Expand All @@ -163,7 +165,9 @@ describe("Test ErrorHandlerMiddleware", () => {
const ctx = Context.create(broker, eventEndpoint);

return newHandler(ctx)
.catch(protectReject)
.catch(err => {
expect(err).toBeInstanceOf(MoleculerError);
})
.then(() => {
const err = broker.errorHandler.mock.calls[0][0];

Expand All @@ -181,30 +185,5 @@ describe("Test ErrorHandlerMiddleware", () => {
});
});
});

it("should logging if throw further", () => {
broker.errorHandler = jest.fn(err => Promise.reject(err));
let error = new MoleculerError("Some error");
let handler = jest.fn(() => Promise.reject(error));

const newHandler = mw.localEvent.call(broker, handler, action);
const ctx = Context.create(broker, eventEndpoint);
ctx.id = "123456";
ctx.nodeID = "server-2";

jest.spyOn(broker.logger, "error");

return newHandler(ctx)
.catch(protectReject)
.then(() => {
const err = broker.errorHandler.mock.calls[0][0];

expect(err).toBe(error);
expect(err.ctx).toBe(ctx);

expect(broker.logger.error).toHaveBeenCalledTimes(1);
expect(broker.logger.error).toHaveBeenCalledWith(err);
});
});
});
});
8 changes: 4 additions & 4 deletions test/unit/service-broker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2780,7 +2780,7 @@ describe("Test broker.emit", () => {
]
]);
broker.localBus.emit = jest.fn();
broker.registry.events.callEventHandler = jest.fn();
broker.registry.events.callEventHandler = jest.fn(() => Promise.resolve());

it("should call the local handler", () => {
expect(broker.transit).toBeUndefined();
Expand Down Expand Up @@ -3066,7 +3066,7 @@ describe("Test broker.emit with transporter", () => {
]
]);
broker.localBus.emit = jest.fn();
broker.registry.events.callEventHandler = jest.fn();
broker.registry.events.callEventHandler = jest.fn(() => Promise.resolve());
broker.getEventGroups = jest.fn(() => ["mail", "payment"]);

it("should call sendEvent with ctx", () => {
Expand Down Expand Up @@ -3634,7 +3634,7 @@ describe("Test broker broadcast", () => {

describe("Test broker broadcastLocal", () => {
let broker = new ServiceBroker({ logger: false, nodeID: "server-1" });
broker.emitLocalServices = jest.fn();
broker.emitLocalServices = jest.fn(() => Promise.resolve());
broker.localBus.emit = jest.fn();

it("should call emitLocalServices without payload", () => {
Expand Down Expand Up @@ -3897,7 +3897,7 @@ describe("Test registry links", () => {
broker.registry.getLocalNodeInfo = jest.fn();
broker.registry.events.getGroups = jest.fn();
broker.registry.events.getAllEndpoints = jest.fn(() => [{}]);
broker.registry.events.emitLocalServices = jest.fn();
broker.registry.events.emitLocalServices = jest.fn(() => Promise.resolve());

it("should call registry.getLocalNodeInfo", () => {
broker.getLocalNodeInfo();
Expand Down

0 comments on commit 317e68b

Please sign in to comment.