Getting `undefined` value even after attaching socket to `ctx` in `beforeCall()` hook in moleculer.io

593 Views Asked by At

I am using moleculerjs to handle microservices on the backend, and with one of the front-end applications I am handling the communication over sockets. To do that I am using moleculer.io. The problem I'm running into is that, even though I am attaching the socket to ctx in the onBeforeCall() hook, the socket is not there when I console.log ctx in the controller function.

My gateway looks like this (notice the socket is being added to the ctx object in the onBeforeCall() hook:

const SocketIOService = require("moleculer-io");

module.exports = {
  name: 'oas',
  mixins: [SocketIOService],

  settings: {
    port: 5000,
    io: {
      namespaces: {
        '/': {
          events: {
            'call': {
              aliases: {
                'auth.register': 'oas.controllers.auth.register'
              },
              whitelist: [
                '**',
              ],
              onBeforeCall: async function(ctx, socket, action, params, callOptions) { // before hook
                console.log('socket: ', socket); // This exists here
                ctx.socket = socket; // Here I attach the socket to the ctx object
              },
              onAfterCall: async function(ctx, socket, res) { // after hook
                // console.log('after hook', res)
                // res: The response data.
              }
            }
          }
        }
      }
    },

    events: {},

    actions: {}
  }
};

And my auth.service looks like this - notice the register() function that tries to access ctx.socket:

"use strict";

/**
 * @typedef {import('moleculer').Context} Context Moleculer's Context
 */

module.exports = {
    name: "oas.controllers.auth",

    /**
     * Settings
     */
    settings: {

    },

    /**
     * Dependencies
     */
    dependencies: [],

    /**
     * Actions
     */
    actions: {
    async register(ctx) {
      console.log('ctx.socket: ', ctx.socket); // This is undefined

      // Other code...
    },

    /**
     * Events
     */
    events: {

    },

    /**
     * Methods
     */
    methods: {

    },

    /**
     * Service created lifecycle event handler
     */
    created() {

    },

    /**
     * Service started lifecycle event handler
     */
    async started() {

    },

    /**
     * Service stopped lifecycle event handler
     */
    async stopped() {

    }
};

Here in the register() function that gets called, ctx.socket is undefined. What am I missing here? I assume that onBeforeCall() is designed to be used for exactly this kind of purpose, but perhaps I'm misunderstanding something.

Is there a different way I should or could approach this to ensure the socket is available in the called function? And just to clarify, the socket is available in the onBeforeCall() hook. I need to figure out how to make it available down the line.

2

There are 2 best solutions below

1
On BEST ANSWER

In the end I found a way to do this. Instead of attaching the socket to ctx directly, which as @Icebob pointed out, you can't do, I was able to attach it ctx.meta, like so:

onBeforeCall: async function(ctx, socket, action, params, callOptions) { // before hook
  ctx.meta.socket = socket;
},

By doing this I was able to successfully access the socket in my register() function.

0
On

You can't do that. You can't put anything to the ctx. The ServiceBroker will serialize & transfer only the ctx.params and ctx.meta properties. But you can't put the socket into them because the Socket object what you like is not serializable, so you can't access it in remote services. It can work in a monolith project, not in a microservices project.