A
A
Azik282015-07-15 16:40:48
JavaScript
Azik28, 2015-07-15 16:40:48

How to send a response to a request not immediately, but after a certain amount of time?

I am sending an image from an Android client to a Node.js server where it is processed by a Python program. I'm linking Node.js to a Python program through NPM's Python-Shell package or library. I need to send the processing result back to the client as a response to a request.
But due to the asynchronous architecture of Node.js, the response is sent immediately, without waiting for the execution and completion of processing, which takes somewhere around 30-40 seconds. As a result, the Android client receives an empty response.
Also, I can't use res.write() multiple times. After I used it once, I guess the connection is dropping. So I can't use res.write() or res.send() in an event handler. And so I accumulate all messages from the Python program to the Node.js server into a separate array, which I try to send, but again, I need to wait for the Python program to execute.
So, how can you send a response after the program has completed and the result is ready to be sent? Is there another way to send the output (which is text) to an Android client?
Node.js code

app.post('/', rawBody, function (req, res) {
//rawBody is a function that receives chunks of image binary and creates a req.rawBody

if (req.rawBody && req.bodyLength > 0) {
    console.log("entered file writing");
    var timestamp = new Date().getTime().toString();
    var filename = 'Image'+timestamp+'.jpg';
    fs.writeFile(filename, req.rawBody);
    fs.writeFile('imagelist.txt', __dirname+ '/' + filename);
    //here I create an instance of PythonShell and execution of //testfile.py starts
    var pyshell = new PythonShell('testfile.py', options);
    //I store in the output all the messages from Python
    var output = [];
    // whenever python prints any output this event is emitted
    pyshell.on('message', function(message, error){
            if (error) throw error;
            console.log(message);
            //try to write the message into response
            res.write(message);
            output.push(message);
    });

    pyshell.end(function(err) {

            console.log('python finished');
            //send response
            res.end();
    });

    pyshell.on('error',function(err){
            console.log(err);
    });

} else {
    res.send(500);
}

});

This is how I get the response on the android client:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
       conn.setRequestMethod("POST");

       conn.setDoInput(true);
       conn.setDoOutput(true);
       conn.setRequestProperty("Connection", "Keep-Alive");
       conn.setRequestProperty("Cache-Control", "no-cache");

        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
        conn.setReadTimeout(80000);
        conn.setConnectTimeout(80000);
        InputStream in = new BufferedInputStream(conn.getInputStream());

        BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        StringBuilder stringBuilder = new StringBuilder();

       while (true) {
                    line = responseStreamReader.readLine();
                    if (line != null) {
                        System.out.print("accepted new response particle " + line);
                        stringBuilder.append(line).append("\n");
                        System.out.print(stringBuilder.toString());
                        break;
                    } 
          }
          //old version
        /*while ((line = responseStreamReader.readLine()) != null) {
            stringBuilder.append(line).append("\n");
            //System.out.print(stringBuilder.toString());
        }*/
        responseStreamReader.close();

        String response = stringBuilder.toString();
        System.out.println(response);

        in.close();
        conn.disconnect();

Answer the question

In order to leave comments, you need to log in

1 answer(s)
T
Timur Shemsedinov, 2015-07-15
@MarcusAurelius

Replace all synchronous operations like writeFileSync with asynchronous counterparts so that they do not block the processing thread, and send a response after 30-40 seconds, even after 3-5 minutes is normal, this will work like long pooling, i.e. until the HTTP timeout ends. Only you can not block the processing thread, otherwise parallel requests will not be accepted.
UPD: I also noticed that req.rawBody is your function that reads and glues all the chunks of the file, so here it is without a callback, you made it synchronous too, it's bad, look how I get a series of chunks and glue them: impress. application.js#L479-L489In general, it is clear that you have only partially mastered the asynchronous approach and mix it with the synchronous one, which does not allow parallel processing of several such requests in one node thread. It is not necessary to use file streams and pipes here, but it is possible. Only then you need to hang up the launch of the python on the req.on('end',...) or file.res.on('finish',...) event of the FileStream into which you pipe req.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question