0

I'm working on a Node.js application which accepts submitted Python code and runs test suites on those submissions. I've been using python-shell package to run Python within Node.js. When submissions fail or pass test cases, everything is fine. The problem appears when a Python script contains an endless loop. In this case the python-shell instance never terminates.
I've checked some of stack overflow already asked questions, such as How to set a time limit to run asynchronous function in node.js?, Start and Stop Python Script from NodeJS? and How can I stop PythonShell but nothing seems to deal with endless loops within scripts. I want to terminate my judgeRoutine() if the promise is not resolved within several seconds. I've tried to use timeout and promises to address the problem but so far to no avail. I include the code that I have:

//judge.js
const {PythonShell} = require('python-shell')

const fs = require('fs');

function judgeRoutine(){
    let output=""
    return new Promise(function(resolve, reject){
        PythonShell.run('./test.py', null,function(err, result){
            if(err){
                return err
            }
            output = result[1]
            console.log(output)

            //perform DB operations based on output value

            return resolve(output)
        })
        setTimeout(function(){if (output===""){
            return reject(new Error("Time out"));
        }
        else{
            resolve(output)
        }} ,1000)
    })
    .catch(err => console.log(err))
}

function runJudge(){
    new Promise(function(resolve, reject){
        //copy scripts into the folder
        //solution2.py contains an endless loop
        fs.copyFile('./submissions/solution2.py', './solution.py', (err) => {
            if (err) throw err;
            console.log('File was copied to destination');
        });

        fs.copyFile('./tests/test35345.py', './test.py', (err) => {
            if (err) throw err;
            console.log('File was copied to destination');
        })    
    }).then(judgeRoutine()).then(value => console.log("resolve value", value)).catch(err=> {if (err.name==="Time out"){
        reject("Time out")
    }})
}

module.exports={runJudge}

I would be happy to get any suggestions.

4
  • A Promise represents an asynchronously derived result, not the asynchronous process itself. Force-rejecting a Promise won't automatically cause the process to be terminated. If you have a hanging process, you will need to do two things - (1) issue a (shell) command to kill the process; (2) force-reject the promise. Commented Apr 24, 2020 at 3:27
  • You can't promisify two asynchronous processes with one new Promise(...). Your two copyFile() calls will need to be independently promisified and either chained with .then() (to serialise them) or the two Promises aggregated with Promise.all() (having initiated the two processes to run in parallel). Commented Apr 24, 2020 at 3:31
  • .then(judgeRoutine()) should read .then(judgeRoutine). Commented Apr 24, 2020 at 3:32
  • runJudge() should return Promise. Commented Apr 24, 2020 at 3:33

1 Answer 1

1

I included the code snippet that I used to stop an infinite loop in a python script that in running on my Node.js server.

Here I just created a simple promise to run the python script asynchronously to not to block the main thread. But I also added a removeEventlistener function that will stop running the python script after a certain number of time. You can adjust the value as per your need.

Also, you might have noticed that I didn't use any third party library and instead used the one built into Node js. Anyway, hope that it will give you an idea as to how to stop long running process of python scripts in Node.js

const pythonPromise = () => {
  return new Promise((resolve, reject) => {
    const python = spawn("python", ["./script.py"]);

    const print = (data) => {
      console.log(data.length);
      console.log(data);
      resolve(data.toString());
    };
    python.stdout.on("data", print);

    setTimeout(() => {
      python.stdout.off("data", print);
      resolve("Infinite code detected");
    }, 5000);

    python.stderr.on("data", (data) => {
      reject(data.toString());
    });
  });
};

async function runCode() {
  const value = await pythonPromise().catch(console.log);
  console.log(value);
} 

runCode()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.