Skip to content

Commit

Permalink
Merge pull request #1270 from DonVietnam/issue-1241
Browse files Browse the repository at this point in the history
Add hook middlewares interceptors to preserve call context with call middlewares.
  • Loading branch information
icebob authored Feb 3, 2024
2 parents 7560626 + 3ca8041 commit e39e675
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 3 deletions.
13 changes: 10 additions & 3 deletions src/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class MiddlewareHandler {
this.list = [];

this.registeredHooks = {};

this.middlewareInterceptors = {};
}

add(mw) {
Expand All @@ -43,9 +45,14 @@ class MiddlewareHandler {

Object.keys(mw).forEach(key => {
if (isFunction(mw[key])) {
if (Array.isArray(this.registeredHooks[key]))
this.registeredHooks[key].push(mw[key]);
else this.registeredHooks[key] = [mw[key]];
const handle = isFunction(this.middlewareInterceptors[key])
? this.middlewareInterceptors[key](mw[key])
: mw[key];
if (Array.isArray(this.registeredHooks[key])) {
this.registeredHooks[key].push(handle);
} else {
this.registeredHooks[key] = [handle];
}
}
});

Expand Down
16 changes: 16 additions & 0 deletions src/service-broker.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ class ServiceBroker {

// Middleware handler
this.middlewares = new MiddlewareHandler(this);
this.middlewares.middlewareInterceptors["call"] = this.interceptCallMiddleware;

// Service registry
this.registry = new Registry(this);
Expand Down Expand Up @@ -383,6 +384,21 @@ class ServiceBroker {
this.metrics.set(METRIC.MOLECULER_BROKER_MIDDLEWARES_TOTAL, this.middlewares.count());
}

/**
* It is necessary to keep the context of the call when using call middleware.
*/
interceptCallMiddleware(createMiddleware) {
return next => {
let result = null;
const call = createMiddleware((...args) => (result = next(...args)));
return (...args) => {
const promise = call(...args);
if (result) promise.ctx = result.ctx;
return promise;
};
};
}

/**
* Register Moleculer Core metrics.
*/
Expand Down
61 changes: 61 additions & 0 deletions test/integration/middlewares.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,67 @@ const utils = require("../../src/utils");
const { protectReject } = require("../unit/utils");

describe("Test middleware system", () => {
describe("Test hook middleware interceptors.", () => {
const broker = new ServiceBroker({
logger: false,
validator: false,
internalMiddlewares: false,
middlewares: [
{
call(next) {
return (actionName, params, opts) => {
return next(actionName, params, opts).then(res => {
return res;
});
};
}
},
{
call(next) {
return (actionName, params, opts) => {
return next(actionName, params, opts).then(res => {
return Promise.resolve(res + "!");
});
};
}
}
]
});

broker.createService({
name: "contextDataPassedTest",
actions: {
setContextMeta: {
handler(ctx) {
ctx.meta.$metainfo = "testmeta";
}
}
}
});

broker.createService({
name: "test",
actions: {
testAction: {
async handler(ctx) {
await ctx.call("contextDataPassedTest.setContextMeta");
return ctx.meta.$metainfo;
}
}
}
});

beforeAll(() => broker.start());
afterAll(() => broker.stop());

it("The context is passed through the call middlware.", async () => {
const p = broker.call("test.testAction");
await expect(p).resolves.toBe("testmeta!");
expect(p.ctx).toBeDefined();
expect(p.ctx.meta.$metainfo).toBe("testmeta");
});
});

describe("Test with sync & async middlewares", () => {
let flow = [];
let mw1Sync = {
Expand Down
26 changes: 26 additions & 0 deletions test/unit/service-broker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,32 @@ describe("Test ServiceBroker constructor", () => {
});
});

describe("Test broker.interceptCallMiddleware", () => {
const broker = new ServiceBroker({
logger: false,
transporter: null
});

it("should preserve the context of the call", async () => {
const next = () => {
const promise = Promise.resolve("next-result");
promise.ctx = { test: "test" };
return promise;
};

const createMiddleware = jest.fn(next => (...args) => {
return next(...args).then(() => "middleware-result");
});

const createInterceptedMiddleware = broker.interceptCallMiddleware(createMiddleware);

const result = createInterceptedMiddleware(next)();

expect(result.ctx).toEqual({ test: "test" });
await expect(result).resolves.toBe("middleware-result");
});
});

describe("Test broker.start", () => {
describe("without transporter", () => {
let schema;
Expand Down

0 comments on commit e39e675

Please sign in to comment.