Node js get and set data from different process
Asked Answered
W

5

29

I've node application which done spawn(child process) to and application, the application have host and port:

var exec = require('child_process').spawn;
var child = exec('start app');
console.log("Child Proc ID " + child.pid)
child.stdout.on('data', function(data) {
    console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
    console.log('stdout: ' + data);
});
child.on('close', function(code) {
    console.log('closing code: ' + code);
});

some application will start immediately and some application will take some time 10 - 20 sec until they start.

Now I use the node http proxy to run the app and the problem is that Im getting error when the use want to run the app before it up and running. Any idea how somehow I can solve this issue?

proxy.on('error', function (err, req, res) {
    res.end('Cannot run app');
});

Btw, I cannot send response 500 in proxy error due to limitation of our framework. Any other idea how can I track the application maybe with some timeout to see weather it send response 200.

UPDATE - Sample of my logic

httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({});
http.createServer(function (req, res) {
    console.log("App proxy new port is: " + 5000)
    res.end("Request received on " + 5000);
}).listen(5000);

function proxyRequest(req, res) {
    var hostname = req.headers.host.split(":")[0];
    proxy.web(req, res, {
        target: 'http://' + hostname + ':' + 5000
    });  

    proxy.on('error', function (err, req, res) {
        res.end('Cannot run app');
    });
}
Wylen answered 29/10, 2015 at 14:28 Comment(2)
you mention that you have framework limitations - can you go into more detail? It's hard to know what sort of solutions are available to you if we don't know what we can and can't do. Do you have control over the child process(es) that is/are being spawned?Perpetrate
What do you expect to happen if there is an request sent and app is not available yet?Trimming
G
1

What you need is to listen for the first response on your proxy and look at its status code to determine whether your app started successfully or not. Here's how you do that:

proxy.on('proxyRes', function (proxyRes, req, res) {
  // Your target app is definitely up and running now because it just sent a response;
  // Use the status code now to determine whether the app started successfully or not
  var status = res.statusCode;
});

Hope this helps.

Gendron answered 13/1, 2016 at 0:55 Comment(6)
Thanks but when and how should I do that? Assume I put your code and the user click on the browser to run the app which still is not up so first thing he will see the error, so how can I overcome this ? maybe you are an expert in this topic and I miss something here :) Thank you!Wylen
So if the user opens the browser and the browser makes a request to your app, then the proxy should emit the 'proxyRes' event. If your app is not ready, then the browser will not receive a response until it is. So I think this should work.Gendron
The error should not come before unless there was an actual error starting up your proxy, but if your app starts fine, then you should not get an error if you don't do anything before the 'proxyRes' event.Gendron
Thanks I've try it but it doesn't work :( any other idea?Wylen
It would be good to see more of your code as I can get a better sense of the entire execution flow start-to-endGendron
HI Please see my update ,In the spawn I trigger the app and in the reverse proxy I call to it...Wylen
V
1

Not sure if it make sense , In your Main App the experience should start with a html page and each child process should have is own loader.

So basically , you need a http Handler, which linger the request until the the child process is ready. So just make and ajax call from the html , and show loading animation till the service is ready .

//Ajax call for each process  and update the UI accordingly   
$.get('/services/status/100').then(function(resp) {
   $('#service-100').html(resp.responseText);
})

//server side code (express syntax)
app.get('/services/status/:id ', function(req,res) {
     // Check if service is ready 
     serviceManager.isReady(req.params.id, function(err, serviceStats) {
         if(err) {
            //do logic err here , maybe notify the ui if an error occurred
            res.send(err);
            return;
         }
         // notify the ui , that the service is ready to run , and hide loader
         res.send(serviceStats);
     });
})
Vacancy answered 17/1, 2016 at 15:21 Comment(0)
T
1

I am not sure i understand the question correctly, but you want to wait for a child process to spin on request and you want this request to wait for this child process and then be send to it? If that is so a simple solution will be to use something like this

    var count = 0;//Counter to check
    var maxDelay = 45;//In Seconds
    var checkEverySeconds = 1;//In seconds
    async.whilst(
        function () {
            return count < maxDelay;
        },
        function (callback) {
            count++;
            self.getAppStatus(apiKey, function (err, status) {
                if (status != 200) {
                    return setTimeout(callback, checkEverySeconds * 1000);

                } 
                continueWithRequest();

            });
        },
        function (err) {
            if (err) {
                return continueWithRequest(new Error('process cannot spin!'));
            }
        }
    );

The function continueWithRequest() will forward the request to the child process and the getAppStatus will return 200 when the child process has started and some other code when it is not. The general idea is that whilst will check every second if the process is running and after 45 second if not it will return an error. Waiting time and check intervals can be easily adjusted. This is a bit crude, but will work for delaying the request and setTimeout will start a new stack and will not block. Hope this helps.

Telfore answered 11/3, 2016 at 11:48 Comment(0)
S
1

If you know (around) how much time the app takes to get up and running, simply add setTimeout(proxyRequest, <Time it takes the app to start in MS>)

(There are most likely more smart/complicated solutions, but this one is the easiest.)

Silvana answered 16/3, 2016 at 11:50 Comment(0)
C
1

Why not use event-emitter or messenger?

var eventEmitter = require('event-emitter')
var childStart = require('./someChildProcess').start()

if (childStart !== true) {
        eventEmitter.emit('progNotRun', {
            data: data
        })
} 

function proxyRequest(req, res) {

    var hostname = req.headers.host.split(":")[0];
    proxy.web(req, res, {
        target: 'http://' + hostname + ':' + 5000
    });  

    eventEmitter.on('progNotRun', function(data) {
        res.end('Cannot run app', data);
    })
}
Chemarin answered 24/4, 2016 at 3:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.