Search code examples
node.jsoptaplanneroptapy

Integrating Optapy into Node JS web service


I am working on a project in which I need to run a python script which is based on an optapy solution. So after running the web service, I was expecting to get as response the solution provided by optapy. But I just received this line which is autogenerated by optapy after running the solver. 16:28:03.158 [main ] INFO Solving started: time spent (186), best score (-45init/0hard/-2soft), environment mode (REPRODUCIBLE), move thread count (NONE), random (JDK with seed 0). And after few moment I recieved this error in the console

node:internal/errors:465
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:372:5)
    at ServerResponse.setHeader (node:_http_outgoing:576:11)
    at ServerResponse.header (C:\Users\KaryGauss\Desktop\OSPlanner Service\OSPlanner_NodeJS\node_modules\express\lib\response.js:794:10)
    at ServerResponse.send (C:\Users\KaryGauss\Desktop\OSPlanner Service\OSPlanner_NodeJS\node_modules\express\lib\response.js:174:12)
    at Socket.<anonymous> (C:\Users\KaryGauss\Desktop\OSPlanner Service\OSPlanner_NodeJS\controllers\test.js:10:13)
    at Socket.emit (node:events:527:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10)
    at Pipe.onStreamRead (node:internal/stream_base_commons:190:23) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

This is the controller of my route in which I called the script python :

const spawn = require('child_process').spawn;

const test = (req, res) => {
    const py = spawn(process.env.PYTHON, [process.env.SCRIPT]);
    py.stdout.on("data", async (data) => {
        //console.log(`stdout: ${data}`);
        let allData = "";
        allData += data;
        // console.log(data.toString());
        res.send(allData.toString());
    });
    py.stderr.on("data", (data) => {
        console.log(`stderr: ${data}`);
        res.send(data);
    });
}

module.exports = {
    test
}

And this my main function for my Optapy solution

import sys
from domain import Reservation, ReservationSchedule, generate_problem
from constraints import define_constraints
import optapy.config
from optapy.types import Duration
from optapy import solver_factory_create

solver_config = optapy.config.solver.SolverConfig() \
    .withEntityClasses(Reservation) \
    .withSolutionClass(ReservationSchedule) \
    .withConstraintProviderClass(define_constraints) \
    .withTerminationSpentLimit(Duration.ofSeconds(30))
solver_factory = solver_factory_create(solver_config)
solver = solver_factory.buildSolver()
solution = solver.solve(generate_problem())

print(solution)

Solution

  • My guess what is happening is you are sending multiple response per request, which is not allowed (see https://stackoverflow.com/a/48123354). In particular, what I think is happening is your py.stdout.on function is being called for every line in the log and for the final solution.

    Since logging is also done on standard output, it should be disabled so it does not interfere with the communication between Node and Python. This can be done by setting the logging level, as explained in the logging section of the user guide:

    import logging
    
    logging.getLogger('optapy').setLevel(logging.ERROR)
    

    This modifies the logger to only log when an error happens, and thus prevent any log lines from showing during/after solving (unless an error occurs).