I would disagree with this statement, but only narrowly, once you start talking about proxies and reverse proxies and things of that nature, it becomes much harder because the client isn’t directly connected anymore. In most of todays environments you are right that it is really hard to know if a remote client went away or if a request was actually successfully returned to the remote client (and not just any intermediary proxies/servers that may be buffering the request).
It is hard to do in Python based threaded servers because even though the code is running in a thread, and the main thread knows about the connection being dropped, there’s no way for the main thread to cancel the running of the worker thread and notify it. pthread_cancel does not work, and there is no good way to signal to the thread to stop running code or to interrupt it, especially during heavy computation. HTTP/1.1 also makes this somewhat more difficult, in that the only way for the main thread to know is to continue telling the kernel it wants to read from the socket the client is connected on, with HTTP pipelining the client can send multiple requests at once, and we’d have to buffer those requests, otherwise the call to select()/poll() becomes a busy loop because each time we call select()/poll() the OS would tell us the socket is ready for reading. Thankfully HTTP pipelining these days is very rare because of incredibly poor support for having multiple requests in flight, while the response being returned would close the connection due to an error (the client would have to retry any in-flight requests that were pipelined but not replied to). You can emulate it somewhat by checking to see during various points of computation whether the client has gone away, and then manually acting upon it, and waitress has support for that. It is not enabled by default because of the HTTP pipelining issue, and the issue of spinning on select(), but it is configurable to attempt to buffer up to X requests by setting the flag `channel_request_lookahead` to something that is non-zero. There’s just no predefined way to do it across WSGI servers, nor does pyramid_tm provide any helpers for it since it can’t add those checks for you as you are generating your response. This is a waitress extension. The feature was introduced in this PR: https://github.com/Pylons/waitress/pull/310 I don’t think there’s good example of how to use it in the documentation, but here’s a quick and dirty example: import logging import time log = logging.getLogger(__name__) def application(environ, start_response): check = environ["waitress.client_disconnected"] for i in range(10): # do some computation log.debug("Starting computation for %d", i) time.sleep(2) log.debug("Completed computation for %d", i) if check(): log.debug("Remote client went away, processed %d items", i + 1) break start_response( "200 OK", [ ("Content-Type", "application/octet-stream"), ], ) return [b"work completed"] if __name__ == "__main__": import waitress logging.basicConfig( format="%(asctime)-15s %(levelname)-8s %(name)s %(message)s", level=logging.DEBUG, ) waitress.serve(application, channel_request_lookahead=5) Now start this process, and then run curl but hit Ctrl + C on curl a second or two after you start curl: You should see something like the following: python client_disconnected.py 2022-03-08 20:12:01,081 INFO waitress Serving on http://0.0.0.0:8080 2022-03-08 20:12:04,206 DEBUG __main__ Starting computation for 0 2022-03-08 20:12:06,211 DEBUG __main__ Completed computation for 0 2022-03-08 20:12:06,211 DEBUG __main__ Starting computation for 1 2022-03-08 20:12:08,215 DEBUG __main__ Completed computation for 1 2022-03-08 20:12:08,216 DEBUG __main__ Remote client went away, processed 2 items 2022-03-08 20:12:08,217 INFO waitress Client disconnected while serving / An app developer who knows that the clients are always going to be directly connected, can add code similar to the above in their response code and do these checks manually during their computation, and if they raise an error, pyramid_tm will appropriate abort the transaction, and pyramid should run the exception view machinery (although that response will never make it back to the client, it should be possible to use it at that point to do any extra cleanup or whatnot though) Hopefully Andrew Free this helps somewhat, in that it is possible, it’s just extra code you have to write and be aware of, it is not something that comes for free, and requires that you use waitress, and it requires that you set the `channel_request_lookhead` flag, and it requires that you know your clients are directly connected. Caveat emptor. Thanks, Bert JW Regeer > On Mar 7, 2022, at 13:05, Jonathan Vanasco <[email protected]> wrote: > > Just to clarify the above comment, this concept isn't really possible with > any internet technology in general, not just Pyramid. > On Thursday, February 17, 2022 at 8:35:25 PM UTC-5 Bert JW Regeer wrote: > No, this is not possible *. > > * Except under some very narrow circumstances, but none that are easy to use > or directly supported in Pyramid > >> On Feb 17, 2022, at 13:12, Andrew Free <[email protected]> wrote: >> >> Is there a way to subscribe to any events of a dropped/lost connection? >> >> For example, if the user closed the browser window in the middle of a >> request. I am using pyramid_tm and having a hard time finding a method for >> this. I just want to run some code based on the request object state in the >> event that the response doesn't make it back to the client and the >> transaction does not complete. I've looked into the exception_view_config >> and this doesn't appear to help. Would a tween be the best way to handle >> this? >> Thanks. >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "pylons-discuss" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/pylons-discuss/cab03e28-c370-4dcb-917a-7b5d36e7a86fn%40googlegroups.com. > > > -- > You received this message because you are subscribed to the Google Groups > "pylons-discuss" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/pylons-discuss/113341b5-529b-4bb8-b1e8-5a3d28ce028dn%40googlegroups.com. -- You received this message because you are subscribed to the Google Groups "pylons-discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/pylons-discuss/3B2C7EFF-A9A1-40CE-9B0A-2CB01B6EC5A0%400x58.com.
signature.asc
Description: Message signed with OpenPGP
