moleculer
moleculer copied to clipboard
Missing ctx on call middleware
Prerequisites
Please answer the following questions for yourself before submitting an issue.
- [x] I am running the latest version
- [x] I checked the documentation and found no answer
- [x] I checked to make sure that this issue has not already been filed
- [ ] I'm reporting the issue to the correct repository
Expected Behavior
Call-middleware should do not change default behaviours of micro service context handlers. Any information of that behavior in the documentation.
Current Behavior
If I use a call-middleware the context object is missing.
Failure Information
If I call a service from another service so that i have to use ctx.call and change the meta in the end service the calling service get the updated meta, right?
But if I use it with a call-middleware like in the documentation of moleculer middleware described.
call(next) {
return function(actionName, params, opts) {
console.log("The 'call' is called.", eventName);
return next(actionName, params, opts).then(res => {
console.log("Response:", res);
return res;
});
};
},
By the way the call and mcall examples eventName is not available in this scope.
If I use this example the context object is completly missing. See example below.
Steps to Reproduce
Please provide detailed steps for reproducing the issue.
- create broker
- create two services
- add one action two each service
- call one action from service 1 with ctx.call of the action from service 2
- log the meta information // you will see the right value
- add a call-middleware
- run again // you will see the wrong value
Reproduce code snippet
const { ServiceBroker } = require('moleculer');
const broker = new ServiceBroker({
namespace: 'test',
nodeID: 'broker-1',
});
broker.createService({
name: 'test1',
actions: {
test: (ctx) => {
ctx.meta.x = 3;
return 'Hello World';
},
},
});
broker.createService({
name: 'test2',
actions: {
test: (ctx) => {
return ctx.call('test1.test');
},
},
});
broker.start().then(() => {
const meta = { x: 2 };
broker.call('test2.test', {}, { meta }).then((msg) => {
console.log(msg, meta);
});
});
The result should be correct with 3.
Now we add a call-middleware to the broker.
const broker = new ServiceBroker({
namespace: 'test',
nodeID: 'broker-1',
middlewares: [
{
call: (next) => {
return function(actionName, params, opts) {
console.log('The "call" is called.', actionName);
return next(actionName, params, opts).then(
(res) => {
console.log('Response:', res);
return res;
}
);
};
},
},
],
});
Now the result is wrong with 2.
Thats because of the the assignment of the context to the promise object, see p.ctx = ctx. If I use .then in the call-middleware like above. I create a new promise object but without the context.
That's why I wrote the middleware to
const broker = new ServiceBroker({
namespace: 'test',
nodeID: 'broker-1',
middlewares: [
{
call: (next) => {
return function(actionName, params, opts) {
console.log('The "call" is called.', actionName);
const promiseWithContext = next(actionName, params, opts);
const promiseWithoutContext = promiseWithContext.then(
(res) => {
console.log('Response:', res);
return res;
}
);
promiseWithoutContext.ctx = promiseWithContext.ctx;
return promiseWithoutContext;
};
},
},
],
});
Now the result will be correct again with 3.
I don't know whether or how you can fix this. But it will be great if there are any information in the documentation about this behavior.
Context
Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
- Moleculer version: master
- NodeJS version: 10.8
- Operating System: Ubuntu 18.04
Failure Logs
--
If you want to add middleware to calls, use localCall instead of call. The localCall wrapped the action handler, so you have pointer to the ctx. But the call wrapped the broker.call so it will be called before the context creating.
E.g:
const broker = new ServiceBroker({
namespace: "test",
nodeID: "broker-1",
middlewares: [
{
localCall: (next) => {
return function(ctx) {
console.log("The \"call\" is called.", ctx.action.name);
return next(ctx).then(res => {
console.log("Response:", res);
return res;
});
};
},
},
],
});
Yes I know. I use a localCall-Middleware and a remoteCall-Middleware but I want to use the call-Middleware to wrap some information after the response of broker.call comes back from another service but before the broker.call gives the response back to the business logic which used the call.
For the example above:
broker.call('test2.test', {}, { meta }).then((msg) => {
console.log(msg, meta);
});
Here I want to do something between broker.call('test2.test', {}, { meta }) and the .then((msg) => { console.log(msg, meta); });.
The last example I wrote - works totally fine - but for this case I found no information about this behavior in the documentation. Just the implementation of a call-Middleware throwing away the ctx if you not return next(ctx) directly.
That's why I open a issue here then I think it's necessary to know that the call-Middleware can be discard the ctx if you don't assign this to the new promise.