ipkn / crow

Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)
BSD 3-Clause "New" or "Revised" License
7.47k stars 888 forks source link

[Question] how to run a function after sending a response #314

Open arvsr1988 opened 6 years ago

arvsr1988 commented 6 years ago

I have a route where i want to send a 200 response, run a function and then send a request to a callback url. I'm trying to use std::async to achieve this but the code appears to run synchronously. Here's my code.

int long_running_task(std::string callback_url){
    // ... my own code
    return 0;
}
main() {

crow::SimpleApp app;
CROW_ROUTE(app, "/")
    .methods("POST"_method)
    ([](const crow::request& req){
        auto body = crow::json::load(req.body);
        std::string callback_url = body["callback_url"].s();
        cout << "callback url is " << callback_url << "\n";
        future<int> task = std::async(std::launch::async, operations_research::long_running_task, callback_url);
        return crow::response(200);
    });

app.port(8080)
        .multithreaded()
        .run();
}

how can i do what i intend to do?

mrozigor commented 6 years ago

Shouldn't be enough to send request to callback_url in long_running_task (at the end)?

meshula commented 6 years ago

the code runs synchronously because the future task's destructor will block until the task is done. You need to keep the future somewhere else.

arvsr1988 commented 6 years ago

@meshula what do you mean by somewhere else?

I also tried std::thread().detch() but the thread only executes after the application stops.

mrozigor commented 6 years ago

Can you paste code snippet?

meshula commented 6 years ago

What I mean is that the variable named task is scoped to the body of the lambda function, and it's destructor will block at the end of the lambda function execution. If you want the future to not block, it's scope has to be outside of the lambda function. For example, if it exists at the scope of main, it won't block until main finishes.

arvsr1988 commented 6 years ago

small correction. std::thread::detach() does what I want but I'm concerned about the thread management as each request will spawn a new thread. Will crow framework manage the lifecycle of the threads that are detached or will I have to manage it myself?

mrozigor commented 6 years ago

"Detaches the thread represented by the object from the calling thread, allowing them to execute independently from each other.

Both threads continue without blocking nor synchronizing in any way. Note that when either one ends execution, its resources are released.

After a call to this function, the thread object becomes non-joinable and can be destroyed safely."

(http://www.cplusplus.com/reference/thread/thread/detach/)

So it looks like you just create thread object, detach it and forget about it ;) It should return resources as soon as it ends it task.