moleculer icon indicating copy to clipboard operation
moleculer copied to clipboard

Missing ctx on call middleware

Open xynon opened this issue 7 years ago • 2 comments

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.

  1. create broker
  2. create two services
  3. add one action two each service
  4. call one action from service 1 with ctx.call of the action from service 2
  5. log the meta information // you will see the right value
  6. add a call-middleware
  7. 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

--

xynon avatar Nov 12 '18 09:11 xynon

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;
                    });
                };
            },
        },
    ],
});

icebob avatar Nov 13 '18 17:11 icebob

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.

xynon avatar Nov 21 '18 14:11 xynon