[pylons-discuss] Re: Looking for best option for Pyramid deployment

2022-03-15 Thread 'Jonathan Vanasco' via pylons-discuss
We run Pyramid via uwsgi, behind an OpenResty server (Nginx fork with 
embedded lua interpreter).  

IMHO the "best" stack is somewhat dependent on your application.  We have a 
large application and the forking model of uwsgi - combined with many of 
its management hooks - lets us aggressively leverage a lot of efficiencies 
via the copy-on-write memory behavior.  gunicorn was not nearly as 
performant for us with our core app, however it has been more performant on 
other apps.  We've run some smaller apps via waitress as a test, and forgot 
about it for months - it worked perfectly with no complaints.

Caddy is certainly a decent server - and has some of the best https 
termination and ssl certificate management in the field.  It has a built in 
ACME client, and can store provisioned certificates in the cloud, which 
simplifies a lot of devops in clustered environments.

I stay away from Apache and personally don't recommend it.  Nginx (and 
caddy) is far better with concurrent requests and throughput; they also 
have much lighter memory footprints. We can run a lot more uwsgi processes 
behind Nginx than any Apache deployment option - which means we can scale 
to more processes on a node before having to scale onto more nodes in a 
cluster.  In my experience, from a devops management and billing 
perspective, Apache tends to be much more expensive.

On Sunday, February 20, 2022 at 8:53:02 AM UTC-5 tfl...@gmail.com wrote:

> Hi,
> I've built a custom content management framework based on Pyramid; it's a 
> classic web application, based on ZODB and RelStorage with a PostgreSQL 
> backend, a Redis cache and an Elasticsearch index, and I'm actually looking 
> for the best production deployment option.
> Until now, I always used Apache with mod_wsgi, and I'm actually quite 
> happy with it, but I'd like to know if there is a better option with better 
> performance!
> In development mode, I already tried using "native" Waitress server, a 
> GUnicorn server, and I just tried using Pypy with Waitress or GUnicorn but 
> performances were quite "disappointing"!
>
> Any advice?
>
> Best regards,
> Thierry
> -- 
>   https://www.ulthar.net -- http://pyams.readthedocs.io
>

-- 
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/0ef924de-ef7d-4152-bb70-b266f0a368c8n%40googlegroups.com.


Re: [pylons-discuss] Subscribing to connection lost / failed transaction event?

2022-03-15 Thread 'Jonathan Vanasco' via pylons-discuss
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