【问题标题】:Node js get and set data from different processNode js从不同的进程获取和设置数据
【发布时间】:2016-01-29 18:09:40
【问题描述】:

我有节点应用程序,它完成了生成(子进程)到应用程序, 应用程序有主机和端口:

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

一些应用程序将立即启动,而一些应用程序将需要一些时间 10 - 20 秒才能启动

现在我使用节点 http 代理来运行应用程序,问题是当用户想要在应用程序启动和运行之前运行应用程序时出现错误。 知道如何解决这个问题吗?

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

顺便说一句,由于我们框架的限制,我无法在代理错误中发送响应 500。任何其他想法我如何跟踪应用程序可能有一些超时以查看它发送响应 200 的天气。

更新 - 我的逻辑示例

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');
    });
}

【问题讨论】:

  • 你提到你有框架限制——你能说得更详细些吗?如果我们不知道我们能做什么和不能做什么,就很难知道您可以使用什么样的解决方案。您是否可以控制正在生成的子进程?
  • 如果发送了请求但应用程序尚不可用,您预计会发生什么?

标签: javascript node.js child-process spawn node-http-proxy


【解决方案1】:

为什么不使用事件发射器或信使?

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

【讨论】:

    【解决方案2】:

    如果您知道(大约)应用启动和运行所需的时间,只需添加 setTimeout(proxyRequest, <Time it takes the app to start in MS>)

    (很可能有更智能/更复杂的解决方案,但这个是最简单的。)

    【讨论】:

      【解决方案3】:

      我不确定我是否正确理解了这个问题,但是您想等待子进程根据请求旋转并且您希望此请求等待该子进程然后发送给它? 如果这是一个简单的解决方案,那就是使用这样的东西

          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!'));
                  }
              }
          );
      

      函数 continueWithRequest() 会将请求转发给子进程,当子进程启动时 getAppStatus 将返回 200,否则返回一些其他代码。一般的想法是,如果进程正在运行,while 将每秒检查一次,如果没有,则在 45 秒后返回错误。等待时间和检查间隔可以轻松调整。这有点粗略,但适用于延迟请求,setTimeout 将启动一个新堆栈并且不会阻塞。希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        不确定是否有意义,在您的主应用程序中,体验应该从一个 html 页面开始,每个子进程应该有自己的加载器。

        所以基本上,您需要一个 http 处理程序,它会在子进程准备好之前等待请求。因此,只需从 html 进行 ajax 调用,并显示加载动画,直到服务准备好。

        //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);
             });
        })
        

        【讨论】:

          【解决方案5】:

          您需要在代理上侦听第一个响应并查看其状态代码以确定您的应用是否成功启动。这样做的方法如下:

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

          希望这会有所帮助。

          【讨论】:

          • 谢谢,但我应该何时以及如何做呢?假设我输入了您的代码并且用户单击浏览器以运行仍未启动的应用程序,因此他首先会看到错误,那么我该如何克服呢?也许你是这个主题的专家,我在这里错过了一些东西:) 谢谢!
          • 因此,如果用户打开浏览器并且浏览器向您的应用发出请求,那么代理应该发出 'proxyRes' 事件。如果您的应用程序尚未准备好,那么浏览器将不会收到响应,直到它准备好。所以我认为这应该可行。
          • 除非在启动代理时出现实际错误,否则错误不应出现在之前,但如果您的应用程序启动正常,那么如果您在 'proxyRes 之前不执行任何操作,则不应出现错误' 事件。
          • 谢谢,我试过了,但它不起作用:(还有其他想法吗?
          • 很高兴看到您的更多代码,因为我可以更好地了解从头到尾的整个执行流程
          猜你喜欢
          • 2020-05-05
          • 1970-01-01
          • 2014-06-14
          • 1970-01-01
          • 2019-08-11
          • 2021-07-02
          • 2018-03-07
          • 1970-01-01
          • 2020-07-01
          相关资源
          最近更新 更多