Cátia Matos
Cátia Matos

Reputation: 940

Share global object between process nodejs

I'm having troubles with processes with Node.js

So I have a parent/child process implementation to send gps info of a device and I need to share the token from the device between both parent and child.

My problem is that thay dont share that object and the child always ask for a new tokwn. instead of using the same until it expires.

My token is something like:

{"token":"f93cefe254ca873755b3bbbdca2f4c94","timeout":300,"expire":1512552810822}

And when i debug in runChild I always get different values for radioAccess and for each new token I require, I make a new request to the device ...

What can I do to persiste the "radioAcess" global object?

nsGPSService.js

  require('./globals');

var listRoutDirectories = getDirectories(routeDirectory);
for (var i = 0; i < listRoutDirectories.length; i++) {
    var directoryName = listRoutDirectories[i];
    var directoryPath = routeDirectory + '/' + listRoutDirectories[i];
    var directoryFiles = getFiles(directoryPath);

    for (var j = 0; j < directoryFiles.length; j++) {
        var file = directoryFiles[j];
        if (file.indexOf('Controller.js') > -1) {
            global.Controllers[file.replace('Controller.js', '')] = require(directoryPath + '/' + file);
        } else if (file.indexOf('Model.js') > -1) {
            global.Models[file.replace('Model.js', '')] = require(directoryPath + '/' + file);
        } else if (file.indexOf('Database.js') > -1) {
            global.Database[file.replace('Database.js', '')] = require(directoryPath + '/' + file);
        }
    }
}

var child_process = require("child_process");
var argv = require('minimist')(process.argv.slice(2));

//ex: nsGPSService.js -d 1111-11-11-111
var deviceId = argv.d;
var processDevices = [];

function runParent () {
    setTimeout(function() {
    var numDevice = 1;
        createLog('info', __dirname, __filename.slice(__dirname.length + 1, -3), null, 'runParent', "");
        return Database.Devices.getDevices().then(function (devices) {
            return new Promise(function (resolve, reject) {
                async.each(devices, function (device, callback) {   
                    var result = _.filter(processDevices, {"id": device.id});

                    if(result.length == 0) {
                        logger.info('WSController-Service', 'runParent', 'getRadioInfo  --> ', device.id, ' :: ', numDevice++, '/', devices.length);
                        var process = child_process.fork(__dirname + '/nsGPSService.js', ["-d", device.id]);

                        processDevices.push({ "process": process, "id": device.id });

                        process.radioAccess = radioAccess[deviceId] || {};

                        createLog('debug', __dirname, __filename.slice(__dirname.length + 1, -3), device.id, 'runParent', 'process.radioAccess ', process.radioAccess);


                        process.on('message', function(data) {
                            //receber mensagens do filho
                            createLog('debug', __dirname, __filename.slice(__dirname.length + 1, -3), data.deviceId, 'runParent data', data);
                            if(data.reason == "deleted") {
                               //child acabou o processo e informa o parent para remover da lista
                                var index = _.findIndex(processDevices, {"id": data.deviceId});
                                processDevices.splice(index, 1);
                            }
                        });
                        process.on('exit', function(code) {
                            createLog('debug', __dirname, __filename.slice(__dirname.length + 1, -3), device.id, 'runParent', 'Exiting with code', code);   
                        });
                        process.on("uncaughtException", function (error) {
                            createLog('error', __dirname, __filename.slice(__dirname.length + 1, -3), device.id, 'runParent', 'error', error);
                            process.exit(1);
                        });
                    }

                    callback();
                }, function(error) {
                    // createLog('error', __dirname, __filename.slice(__dirname.length + 1, -3), null, 'runParent', 'error', error);
                     error ? reject(error) : resolve();
                });
            }).then(function() {
                runParent()
            }).catch(function(error) {
                createLog('error', __dirname, __filename.slice(__dirname.length + 1, -3), null, 'runParent', 'catch error', error);
                runParent()
            });
        }); 
    },5000);
}

if(!deviceId) {
    createLog('info', __dirname, __filename.slice(__dirname.length + 1, -3), deviceId, 'runParent');
    runParent();
}

function runChild (id) {
    createLog('info', __dirname, __filename.slice(__dirname.length + 1, -3), id, 'runChild', "");
    setTimeout(function() {
        return Database.Devices.getDeviceById(id).then(function(device) {
            process.radioAccess = radioAccess[deviceId] || {};
            createLog('debug', __dirname, __filename.slice(__dirname.length + 1, -3), device.id, 'runChild', 'process.radioAccess 1', process.radioAccess);
            if(!device) {
                process.exit();
                return;
            }
            return Controllers.Gps.getRadioInfo('gps', 'info', {}, device).then(function (data) {
                createLog('debug', __dirname, __filename.slice(__dirname.length + 1, - 3), id, 'runChild', 'data', data);

                createLog('debug', __dirname, __filename.slice(__dirname.length + 1, -3), device.id, 'runChild', 'process.radioAccess 2', process.radioAccess);

                return Controllers.Gps.sendDeviceInfo(data, device);
            }).then(function() {
                return runChild(id);
            }).catch(function (e) {
                createLog('error', __dirname, __filename.slice(__dirname.length + 1, - 3), id, 'runChild callback error', e);
                return runChild(id);    
            });
        });
    }, 5000);
}

 runChild(deviceId);

globals.js

global.radioAccess   = {};

I tried to use the process global and add "process.radioAcess" but parent always give {} and child cant persist the token.

Upvotes: 1

Views: 1053

Answers (1)

HMR
HMR

Reputation: 39320

Here is a working example of how you can do it. Please be careful trying to send messages from processes before they are initialized (example in two.js) and in the main.js I exit processes in a timeout to give two.js a chance to send something to one.js

Debugging this is very hard, I don't know why but chrome debugger cannot attach to the child processes and does not stop at debugger statements. Nor do any of the console.log statements from child processes show.

main.js

const fork = require('child_process').fork;
const path = require('path');

const[one,two] = ["one.js","two.js"]
  .map(
    fileName => [path.resolve(fileName),fileName]
  )
  .map(
    ([file,fileName]) => {
      const x = fork(
        file, 
        [], 
        {
          stdio: [ 'pipe', 'pipe', 'pipe', 'ipc' ],
          silent:false
        }
      );
      x.stderr.on(//doesn't do anything
        'error', 
        data =>
          console.log(`got error from ${fileName}:`,data)
      );
      x.on(
        'message',
        message =>
          (message.type==="relay")
            ? one.send({type:"ping",text:`relayed from ${fileName}: ${message.text}`})
            : console.log(`got message from ${fileName}:`,message.text)
      );
      return x;
    }
  );
setTimeout(
  _=>{
    //do this after two can send relayd message (after the send on the que from two)
    one.send({type:"ping",text:"hello one"})
    one.send({type:"exit"})
    two.send({type:"ping",text:"hello two"})
    two.send({type:"exit"})
  }
  ,100
);

two.js

//process is impossible to debug:
// debugger;//never breaks and about:inspect in chrome
//   after init doesn't show this process either
// console.log("useless in forked process"); console.log doesn't show

const processMessage = message => {
  switch (message.type) {
    case "exit":
      process.send({type:"string",text:"Going to exit."});
      process.exit(0);
      break;
    case "ping":
      process.send({type:"string",text:message.text});
      break;
    default:
      process.send({type:"string",text:"unknown message"});
  }
};

process.on(
  'message',
  message =>
    processMessage(message)
);

//this part is not in one.js
Promise.resolve()
.then(
  //send message after main had time to initialize all processes
  x=>process.send({type:"relay",text:"HELLO THERE ONE"})
)

one.js

Same as two.js but without the last part.

Upvotes: 0

Related Questions