【问题标题】:Is there any programmatic way to break infinite loop in NodeJS?是否有任何编程方法可以打破 NodeJS 中的无限循环?
【发布时间】:2020-03-10 18:00:13
【问题描述】:

归根结底——有没有一种实用的方法(也可能是通过在代码中插入一些 JS 构造)来中断或停止执行期间持久的 JS 代码?例如:它可以被一些process.* 对象构造或类似的东西打断吗?或者其他方式?有效的解决方案甚至可能包括要杀死和/或重新启动的 NodeJS 进程。谢谢!

编辑: 我需要在服务器上执行一些特定的用户代码,使用Function 子句(ala eval,更不用说安全问题了)。我不能在其中插入任何额外的代码,只能将其括起来。我需要的是有可能在 5 分钟后破坏用户代码,如果此时还没有完成。例如:

usercode = 'Some code from the user';
pre_code = 'some controlling code for breaking the user code';
post_code = 'another controlling code';

fcode = pre_code + usercode + post_code;

<preparations for breaking usercode>

(new Function(fcode))(); // This MUST exit in 5 minutes

【问题讨论】:

    标签: node.js asynchronous process infinite-loop


    【解决方案1】:

    编辑:

    回答您的编辑。我现在看到了意图。如果它在 nodejs 中运行,您可以使用 worker_thread 来处理 https://nodejs.org/api/worker_threads.html#worker_threads_worker_workerdata

    例如:

    // main.js
    const runCode = (code) => { 
      const worker = new Worker("./code-executor.js", { workerData: { code: guestCode } });
      const promise = new Promise((resolve) => {
        setTimeout(() => worker.kill(), 60000 * 5);
        worker.on("error", () => {
          return reject(new SomeCustomError())
        });
        worker.on("message", (message) => {
          if(message.success) return resolve(message.result);
          return reject(new Error(message.error));
        });
      });
    
      promise.finally(() => { worker.kill() });
    
      return promise;
    }
    
    // code-executor.js
    
    const { workerData, parentPort } = require("worker_threads");
    const { code } = workerData;
    
    Promise.resolve()
     .then(() => (new Function(fcode))())
     .then((result) => {
       parentPort.postMessage({
         success: true,
         result: value
       })
     })
     .catch((error) => {
       parentPort.postMessage({
         success: true,
         error: error.message
       })
     });
    

    如果在浏览器中https://developer.mozilla.org/en-US/docs/Web/API/Worker WebAPI不完全一样,但逻辑应该差不多

    原创

    杀死一个进程。另请阅读:https://nodejs.org/api/process.html#process_signal_events

    process.kill(pid, "SIGINT")

    “杀死”一个长时间运行的函数,你得破解一下。没有优雅的解决方案。注入一个控制器,它可以在长时间运行的函数之外发生变异。要从外部阻止它,请设置controller.isStopped = true

    
    export const STOP_EXECUTION = Symbol();
    
    function longRunning(controller){
      ... codes
    
      // add stopping point
      if(controller.isStopped) throw STOP_EXECUTION;
    
      ... codes
    
      // add stopping point
      if(controller.isStopped) throw STOP_EXECUTION;
    
      ... codes
    }
    
    // catch it by 
    
    try{
      longRunnning();
    }catch(e){
      switch(true){
        e === STOP_EXECUTION: ...;  // the longRunning function is stopped from the outside
        default: ...;               // the longRunning function is throwing not because of being stopped 
    
      }
    }
    
    

    要点:https://gist.github.com/Kelerchian/3824ca4ce1be390d34c5147db671cc9b

    【讨论】:

    • controller.isStopped如何从外部代码中变异出来?例子?
    • 好的。我明白了,但是它可以在 Vanilla JS(ES6 之前)中实现吗?
    • 你能看一下这个问题的编辑吗?
    • @Thevs 我现在明白你的问题的意图。请参阅我的答案的编辑部分
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 2017-09-13
    • 2012-04-02
    • 2016-07-07
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    相关资源
    最近更新 更多