drogonframework / drogon

Drogon: A C++14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows
MIT License
11.65k stars 1.12k forks source link

Ability to detect client disconnection #2190

Open dkalinowski opened 1 month ago

dkalinowski commented 1 month ago

Is your feature request related to a problem? Please describe. In our project we are trying to use Drogon for very long requests (up to 10 minutes long). While it is possible to detect client disconnection when using async streaming responses (by checking stream->send() return value), it is impossible to detect client disconnection early using standard response. It makes it impossible to stop long running workloads and free server resources upon client disconnection.

Describe the solution you'd like It would be nice to be able to install client disconnection callback. We could use the callback to execute workload stopping mechanism on our end.

Describe alternatives you've considered There is no alternative I know of.

fantasy-peak commented 1 month ago

https://github.com/drogonframework/drogon/pull/2191

dkalinowski commented 1 month ago

2191

This PR added ability to check the connection state in case we have access to http request object. The issue is related to scenario when there is no access to request object, during streaming, example: https://github.com/drogonframework/drogon/blob/master/examples/async_stream/main.cc#L13-L24

@fantasy-peak

nqf commented 1 month ago
    app().registerHandler(
        "/stream",
        [](const HttpRequestPtr & ptr,
           std::function<void(const HttpResponsePtr &)> &&callback) {
            std::thread([=] {
                        while (true)
                        {
                            std::lock_guard lk(mm);
                            std::cout <<"aaaaaaaaaa:" << std::boolalpha
                                      << ptr->connected() << std::endl;
                            std::this_thread::sleep_for(
                                std::chrono::seconds(2));
                        }
            }).detach();

➜  build git:(check-conn) ✗ ./examples/async_stream
20241030 01:19:13.772283 UTC 11147 INFO  Server running on 127.0.0.1:8848 - main.cc:100
20241030 01:19:16.940796 UTC 11148 DEBUG [makeHeaderString] send stream with transfer-encoding chunked - HttpResponseImpl.cc:547
aaaaaaaaaa:true
aaaaaaaaaa:true
aaaaaaaaaa:true
nqf commented 1 month ago

You can still use HttpRequestPtr

dkalinowski commented 3 weeks ago

@nqf even if you can check connection status the way you described, we still have no way to get disconnection information when workload is blocking. The example would be running your example with no while (true), but single blocking operation. The solution would be to have an ability to install disconnection callback in which the caller could define logic to stop the blocking workload.

What do you think about it?

fantasy-peak commented 3 weeks ago

Do you mean that drogon's worker thread is blocked?

dkalinowski commented 3 weeks ago

Yes, consider the example be slightly modified:

    app().registerHandler(
        "/stream",
        [](const HttpRequestPtr & ptr,
           std::function<void(const HttpResponsePtr &)> &&callback) {
            std::thread([=] {
              my_workload->run(); // blocking for 10 minutes
            }).detach();

If we would be able to set up disconnection callback, we could run my_workload->stop() and cancel it to save resources

fantasy-peak commented 3 weeks ago

add a new mr