Thursday, March 9, 2017

How to inject module from different app in Node.js

Leave a Comment

I've two node apps/services that are running together, 1. main app 2. second app

The main app is responsible to show all the data from diffrent apps at the end. Now I put some code of the second app in the main app and now its working, but I want it to be decoupled. I mean that the code of the secnod app will not be in the main app (by somehow to inject it on runtime )

like the second service is registered to the main app in inject the code of it. the code of it is just two modules ,is it possible to do it in nodejs ?

const Socket = require('socket.io-client'); const client = require("./config.json");  module.exports =  (serviceRegistry, wsSocket) =>{     var ws = null;     var consumer = () => {         var registration = serviceRegistry.get("tweets");         console.log("Service: " + registration);         //Check if service is online         if (registration === null) {             if (ws != null) {                 ws.close();                 ws = null;                 console.log("Closed websocket");             }             return         }         var clientName = `ws://localhost:${registration.port}/`         if (client.hosted) {             clientName = `ws://${client.client}/`;         }         //Create a websocket to communicate with the client         if (ws == null) {             console.log("Created");             ws = Socket(clientName, {                 reconnect: false             });             ws.on('connect', () => {                 console.log("second service is connected");             });             ws.on('tweet', function (data) {                 wsSocket.emit('tweet', data);             });             ws.on('disconnect', () => {                 console.log("Disconnected from blog-twitter")             });             ws.on('error', (err) => {                 console.log("Error connecting socket: " + err);             });         }     }     //Check service availability     setInterval(consumer, 20 * 1000); } 

In the main module I put this code and I want to decouple it by inject it somehow on runtime ? example will be very helpful ...

4 Answers

Answers 1

You will have to use vm module to achieve this. More technical info here https://nodejs.org/api/vm.html. Let me explain how you can use this:

  1. You can use the API vm.script to create compiled js code from the code which you want run later. See the description from official documentation

Creating a new vm.Script object compiles code but does not run it. The compiled vm.Script can be run later multiple times. It is important to note that the code is not bound to any global object; rather, it is bound before each run, just for that run.

  1. Now when you want to insert or run this code, you can use script.runInContext API.

Another good example from their official documentation:

'use strict'; const vm = require('vm');  let code = `(function(require) {     const http = require('http');     http.createServer( (request, response) => {      response.writeHead(200, {'Content-Type': 'text/plain'});      response.end('Hello World\\n');    }).listen(8124);     console.log('Server running at http://127.0.0.1:8124/');  })`;   vm.runInThisContext(code)(require); 

Another example of using js file directly:

var app = fs.readFileSync(__dirname + '/' + 'app.js'); vm.runInThisContext(app); 

You can use this approach for the conditional code which you want to insert.

Answers 2

You can create a package from one of your apps and then reference the package in the other app.

https://docs.npmjs.com/getting-started/creating-node-modules

Answers 3

There are several ways to decouple two applications. One easy way is with pub/sub pattern (in case you don't need a response).
(Now if you have an application that is very couple, it will be very difficult to decouple it unless you do some refactoring.)
zeromq offers a very good implementation of pub/sub and is very fast.
e.g.

import zmq from "zmq"; socket.connect('tcp://127.0.0.1:5545'); socket.subscribe('sendConfirmation');  socket.on('message', function (topic, message) {     // you can get the data from message.     // something like:     const msg = message.toString('ascii');     const data = JSON.parse(msg);     // do some actions.     // .....  });  //don't forget to close the socket. process.on('SIGINT', () => {     debug("... closing the socket ....");     socket.close();     process.exit(); });  //----------------------------------------- import zmq from "zmq"; socket.bind('tcp://127.0.0.1:5545'); socket.send(['sendConfirmation', someData]);  process.on('SIGINT', function() {   socket.close(); }); 

This way you could have two different containers (docker) for your modules, just be sure to open the corresponding port.
What i don't understand, is why you inject wsSocket and also you create a new Socket. Probably what I would do is just to send the socket id, and then just use it like:

const _socketId = "/#" + data.socketId;      io.sockets.connected[socketId].send("some message"); 

You could also use another solution like kafka instead of zmq, just consider that is slower but it will keep the logs.
Hope this can get you an idea of how to solve your problem.

Answers 4

You can use npm link feature.

The linking process consists of two steps:

  1. Declaring a module as a global link by running npm link in the module’s root folder
  2. Installing the linked modules in your target module(app) by running npm link in the target folder

This works pretty well unless one of your local modules depends on another local module. In this case, linking fails because it cannot find the dependent module. In order to solve this issue, one needs to link the dependent module to the parent module and then install the parent into the app.

https://docs.npmjs.com/cli/link

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment