Slow Requests on Local Flask Server - python

Just starting to play around with Flask on a local server and I'm noticing the request/response times are way slower than I feel they should be.
Just a simple server like the following takes close to 5 seconds to respond.
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index():
return "index"
if __name__ == "__main__":
app.run()
Any ideas? Or is this just how the local server is?

Ok I figured it out. It appears to be an issue with Werkzeug and os's that support ipv6.
From the Werkzeug site http://werkzeug.pocoo.org/docs/serving/:
On operating systems that support ipv6 and have it configured such as modern Linux systems, OS X 10.4 or higher as well as Windows Vista some browsers can be painfully slow if accessing your local server. The reason for this is that sometimes “localhost” is configured to be available on both ipv4 and ipv6 socktes and some browsers will try to access ipv6 first and then ivp4.
So the fix is to disable ipv6 from the localhost by commenting out the following line from my hosts file:
::1 localhost
Once I do this the latency problems go away.
I'm really digging Flask and I'm glad that it's not a problem with the framework. I knew it couldn't be.

Add "threaded=True" as an argument to app.run(), as suggested here:
http://arusahni.net/blog/2013/10/flask-multithreading.html
For example: app.run(host="0.0.0.0", port=8080, threaded=True)
The ipv6-disabling solution did not work for me, but this did.

Instead of calling http://localhost:port/endpoint call http://127.0.0.1:port/endpoint.
This removed the initial 500ms delay for me.

The solution from #sajid-siddiqi is technically correct, but keep in mind that the built-in WSGI server in Werkzeug (which is packaged into Flask and what it uses for app.run()) is only single-threaded.
Install a WSGI server to be able to handle multi-threaded behavior. I did a bunch of research on various WSGI server performances. Your needs may vary, but if all you're using is Flask, then I would recommend one of the following webservers.
Update (2020-07-25): It looks like gevent started supporting python3 5 years ago, shortly after I commented that it didn't, so you can use gevent now.
gevent
You can install gevent through pip with the command pip install gevent or pip3 with the command pip3 install gevent. Instructions on how to modify your code accordingly are here: https://flask.palletsprojects.com/en/1.1.x/deploying/wsgi-standalone/#gevent
meinheld
gevent is better, but from all the benchmarks I've looked at that involve real-world testing, meinheld seems to be the most straightforward, simplistic WSGI server. (You could also take a look at uWSGI if you don't mind some more configuration.)
You can also install meinheld through pip3 with the command pip3 install meinheld. From there, look at the sample provided in the meinheld source to integrate Flask: https://github.com/mopemope/meinheld/blob/master/example/flask_sample.py
*NOTE: From my use of PyCharm, the line from meinheld import server highlights as an error, but the server will run, so you can ignore the error.

My problem was solved by "threaded=True", but I want to give some background to distinguish my problem from others for which this may not do it.
My issue only arose when running Flask with python3. Switching to python2, I no longer had this issue.
My problem manifested only when accessing the api with Chrome, at which point, Chrome displayed the expected screen, but everything else hung (curl, ffx, etc) until I either reloaded or closed the Chrome tab, at which point everything else that was waiting around returned a result.
My best guess is that Chrome was trying to keep the session open and Flask was blocking the subsequent requests. As soon as the connection from Chrome was stopped or reset, everything else was processed.
In my case, threading fixed it. Of course, I'm now going through some of the links others have provided to make sure that it's not going to cause any other issues.

threaded=True works for me, but finally I figured out that the issue is due to foxyproxy on firefox. Since when the flask app is running on localhost, slow response happens if
foxyproxy is enabled on firefox
slow response won't happen if
foxyproxy is disabled on firefox
access the website using other browsers
The only solution I found is to disable foxyproxy, tried to add localhost to proxy blacklist and tweak settings but none of them worked.

I used Miheko's response to solve my issue.
::1 localhost was already commented out on my hosts file, and setting Threaded=true didn't work for me. Every REST request was taking 1 second to process instead of being instant.
I'm using python 3.6, and I got flask to be fast and responsive to REST requests by making flask use gevent as its WSGI.
To use gevent, install it with pip install gevent
Afterwards, I used the https://gist.github.com/viksit/b6733fe1afdf5bb84a40#file-async_flask-py-L41 to set flask to use gevent.
Incase the link goes down, here's the important parts of the script:
from flask import Flask, Response
from gevent.pywsgi import WSGIServer
from gevent import monkey
# need to patch sockets to make requests async
# you may also need to call this before importing other packages that setup ssl
monkey.patch_all()
app = Flask(__name__)
# define some REST endpoints...
def main():
# use gevent WSGI server instead of the Flask
# instead of 5000, you can define whatever port you want.
http = WSGIServer(('', 5000), app.wsgi_app)
# Serve your application
http.serve_forever()
if __name__ == '__main__':
main()

I got this error when running on hosts other than localhost as well, so for some, different underlying problems may exhibit the same symptoms.
I switched most of the things I've been using to Tornado, and anecdotally it's helped an amount. I've had a few slow page loads, but things seem generally more responsive. Also, very anecdotal, but I seem to notice that Flask alone will slow down over time, but Flask + Tornado less so. I imagine using Apache and mod_wsgi would make things even better, but Tornado's really simple to set up (see http://flask.pocoo.org/docs/deploying/others/).
(Also, a related question: Flask app occasionally hanging)

I had a different solution here. I just deleted all .pyc from the server's directory and started it again.
By the way, localhost was already commented out in my hosts file (Windows 8).
The server was freezing the whole time and now it works fine again.

I run Python 3.8.10 which works fine, but as soon as I switch to Python 3.10.6 responses will be awful slow.
I could get around this problem with changing the precedence to IPv4 in /etc/gai.conf

Related

Is it possible to start Daphne in a python script without using an OS call

Is it possible to run a daphne process or even just Django channels from a python script?
The recommended way to do it, is to run
daphne -b 0.0.0.0 -p 8001 django_project.asgi:channel_layer
I was wondering if I could bind that to a variable and run it the way Tornado could
from tornado.web import Application
application = Application([(r"/", RosbridgeWebSocket), (r"", RosbridgeWebSocket)])
This is kind of a work around, but you may use the subprocess module like this:
subprocess.run(["daphne", "-b 0.0.0.0 -p 8001 django_project.asgi:channel_layer"])
Check this thread Calling an external command in Python for more info on the use of subprocess module.
I am not familiar with Django Channels but have you tried using inmemory or redis Channels directly? You might be able to avoid daphne altogether. From what I understand, daphne seems to be the protocol translator layer so outside clients can communicate with Django through daphne (Django uses wsgi rather than asgi so Django alone cannot handle certain protocols, such as, websocket communication). Tornado does not rely on wsgi.
There are examples in daphne tests:
https://github.com/django/daphne/blob/master/daphne/tests/test_http.py
The inmemory ChannelLayer is not cross-process. I'm not sure if that even matters in your use case. If it does, you can check the other backends (such as redis channels) https://channels.readthedocs.io/en/stable/backends.html
This might be more directly what you are looking for:
https://github.com/django/asgi_redis
have you tried it swap the tornado to NGINX ?
http://masnun.rocks/2016/11/02/deploying-django-channels-using-daphne/
I ran into this same issue...
from daphne.cli import CommandLineInterface
CommandLineInterface().run(('my.asgi', '--bind', ip_address, '--port', '8000'))
Should do the trick. The trouble is that I don't see this documented anywhere and so the API may not be very stable.
This is the same code route as calling Daphne through subprocess:
https://github.com/django/daphne/blob/main/daphne/cli.py#L167
https://github.com/django/daphne/blob/main/daphne/cli.py#L204

Python bottle process reach timeout connection

I have a problem that after certain amount of time my bottle server is not reachable and you get connection reset- timeout connection error.
When checking if the process is running, I found it running, but after killing the process and running it again the server return to serve requests.
Any idea what it could be?
I wrapped most of my functions with exception catching , but didn't helped me to understand the problem.
I wonder if anybody has used bottle and had encountered such problem
My guess is because bottle is single threaded, and it's hanging on a request. I would suggest trying a multi-threaded server, such as cherrypy, to see if that resolves the issue. Then go back and see where the hangup was at.
Install cherrypy
pip install cherrypy
Update your python file
bottle.run(myapp, server='cherrypy')
Would need to see more code to identify any specific issue.

Making apache and gevent(django-socketio) work together

I'm working on a ubuntu 12.04 with python, django and recently django-socketio (https://github.com/stephenmcd/django-socketio).
My problem is when I send something to the server through socket and wait for it to send back, when it doesn't.
the django server is running on default http port(80). And the socketio on 8080 port.
if I access my website like this: 'http://mysite.com/' the pages using socketio does not work at all. But using the 8080 port, everything works!
The reason I don't use the socketio server to handle requests(it has a server that you start by typing a manage.py command) is that I don't know how to do it using apache. Got stuck with setting up the wsgi file. What I know so far is that you have to attach the SocketIOServer to django application and whatever. Have tried this, with no success.
My question is: how can I make this work? Maybe having one handling on one port the other on other port should work. But also tried this.
I really don't want to use ajax since is lot's of async requests.
Something, please!
Thanks in advance.

What is the "nice" way to debug django when requests originate remotely?

When someone is remotely hitting a Django server (say, not with a browser, but with a robot or other automated tool), what is the "nice" way for me to trace what the server is doing, and attempt to debug any problems?
What you should do
Debugging should not be done on a production server, so you should use a development server, where you can basically use manage.py runserver+ import pdb; pdb.set_trace().
Why couldn't you do it
Say your dev server is running on a platform like heroku, you might not be able to control how your script is started. From there, using remote-debugging is possible, and here's how you could do it:
What you could do
If you want to be able to step-in code execution and debug remotely (which is totally innapropriate for a production setup), you could use rpdb. I insist on the fact that you shouldn't be doing this unless you know what you're doing (and provided you're not doing it on a production server!)
Basically, what rpdbdoes is that when you call rpdb.set_trace(), pdb is started and its stdinand stdoutare redirected towards port 4444 (but you can change that of course). You'd then telnet (or netcat, for that matter) to that port and do your debugging thing from there.
Closing words
Really, you shouldn't be doing this.

How do I keep a python HTTP Server up forever?

I wrote a simple HTTP server in python to manage a database hosted on a server via a web UI. It is perfectly functional and works as intended. However it has one huge problem, it won't stay put. It will work for an hour or so, but if left unused for long periods of time when returning to use it I have to re-initialize it every time. Right now the method I use to make it serve is:
def main():
global db
db = DB("localhost")
server = HTTPServer(('', 8080), MyHandler)
print 'started httpserver...'
server.serve_forever()
if __name__ == '__main__':
main()
I run this in the background on a linux server so I would run a command like sudo python webserver.py & to detach it, but as I mentioned previously after a while it quits. Any advice is appreciated cause as it stands I don't see why it shuts down.
You can write a UNIX daemon in Python using the python-daemon package, or a Windows service using the pywin32.
Unfortunately, I know of no "portable" solution to writing daemon / service processes (in Python, or otherwise).
Here's one piece of advice in a story about driving. You certainly want to drive safely (figure out why your program is failing and fix it). In the (rare?) case of a crash, some monitoring infrastructure, like monit, can be helpful to restart crashed processes. You probably wouldn't want to use it to paper over a crash just like you wouldn't want to deploy your air bag every time you stopped the car.
Well, first step is to figure out why it's crashing. There's two likely possibilities:
The serve_forever call is throwing an exception.
The python process is crashing/being terminated.
In the former case, you can make it live forever by wrapping it in a loop, with a try-except. Probably a good idea to log the error details.
The latter case is a bit trickier, because it could be caused by a variety of things. Does it happen if you run the script in the foreground? If not, maybe there's some kind of maintenance service running that is terminating your script?
Not really a complete answer, but perhaps enough to help you diagnose the problem.
Have you tried running it from inside a screen session?
$ screen -L sudo python webserver.py
As an alternative to screen there is NoHup which will ensure the process carries on running after your logged out.
Its worth checking the logs to see why its killed/quitting as well as it may not be related to the operating system but an internal fault.

Categories

Resources