100% with you. That's why I wrote it isn't "really" possible. It is 
possible, just under limited conditions. IIRC, one could also use the COMET 
chunking technique to faciliate this - though that would likely cause some 
client side issues.  If you're doing a direct browser-to-server connection, 
one can somewhat monitor the situation as you described - but most 
deployments use proxies, gateways, load balancers, wsgi, etc.  It's also 
possible the client has an open connection / keepalive into your LAN, but 
one of the services on your network timed out and "dropped" the 
connection.  From the user's vantage, the connection is active; but from 
the server's vantage it's dropped. 

In any event, my point should have been more clear: "Detecting client 
disconnects" isn't a **standard** concept across any web frameworks or 
technologies, and this isn't a deficiency of Pyramid.  It's possible to 
somewhat detect, but it's not something I've ever seen natively supported 
in a framework - whether it's Python, Go, C, Java, Ruby, PHP, etc - because 
of how applications are often deployed in layered environments.

On Tuesday, March 8, 2022 at 10:28:05 PM UTC-5 Bert JW Regeer wrote:

> 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 <jvan...@gmail.com> 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 <andrew...@gmail.com> 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 pylons-discus...@googlegroups.com.
> >> 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 pylons-discus...@googlegroups.com.
> > 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 pylons-discuss+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/d2f50f9a-1510-4e08-a49d-b0fd405cba1dn%40googlegroups.com.

Reply via email to