Showing posts with label uwsgi. Show all posts
Showing posts with label uwsgi. Show all posts

Monday, October 1, 2018

Using uWSGI to proxy certain requests

Leave a Comment

I am trying to send all requests /other to another server, say google for example. As far as I understand the config I should be able to do something like this in the config file:

[uwsgi] master = 1 buffer-size = 65535 die-on-term = true # HTTP http-socket = 0.0.0.0:80 # App module = manage:app # Async processes gevent = 100 processes = 4 route-if = equal:${PATH_INFO};/other http:216.58.204.78,www.google.com 

This does not work as the log just has

error routing request to http server 216.58.204.78 [pid: 9|app: -1|req: -1/11] 172.18.0.1 () {36 vars in 759 bytes} [Thu Sep 20 14:51:55 2018] GET /other => generated 0 bytes in 0 msecs via route() (HTTP/1.1 500) 0 headers in 0 bytes (1 switches on core 99) 

1 Answers

Answers 1

according to the uwsgi doc, you need to specify the external HTTP server address in form of HOST:PORT, for example, with config:

route-if = equal:${PATH_INFO};/s http:220.181.111.188:80,www.baidu.com 

result:

[pid: 5113|app: -1|req: -1/1] 127.0.0.1 () {24 vars in 249 bytes} [Tue Sep 25 17:58:33 2018] GET /s => generated 118322 bytes in 34 msecs via route() (HTTP/1.1 200) 18 headers in 944 bytes (0 switches on core 0) 
Read More

Friday, September 28, 2018

Long running script from flask endpoint

Leave a Comment

I've been pulling my hair out trying to figure this one out, hoping someone else has already encountered this and knows how to solve it :)

I'm trying to build a very simple Flask endpoint that just needs to call a long running, blocking php script (think while true {...}). I've tried a few different methods to async launch the script, but the problem is my browser never actually receives the response back, even though the code for generating the response after running the script is executed.

I've tried using both multiprocessing and threading, neither seem to work:

# multiprocessing attempt @app.route('/endpoint') def endpoint():   def worker():     subprocess.Popen('nohup php script.php &', shell=True, preexec_fn=os.setpgrp)    p = multiprocessing.Process(target=worker)   print '111111'   p.start()   print '222222'   return json.dumps({     'success': True   })  # threading attempt @app.route('/endpoint') def endpoint():   def thread_func():     subprocess.Popen('nohup php script.php &', shell=True, preexec_fn=os.setpgrp)    t = threading.Thread(target=thread_func)   print '111111'   t.start()   print '222222'   return json.dumps({     'success': True   }) 

In both scenarios I see the 111111 and 222222, yet my browser still hangs on the response from the endpoint. I've tried p.daemon = True for the process, as well as p.terminate() but no luck. I had hoped launching a script with nohup in a different shell and separate processs/thread would just work, but somehow Flask or uWSGI is impacted by it.

Update

Since this does work locally on my Mac when I start my Flask app directly with python app.py and hit it directly without going through my Nginx proxy and uWSGI, I'm starting to believe it may not be the code itself that is having issues. And because my Nginx just forwards the request to uWSGI, I believe it may possibly be something there that's causing it.

Here is my ini configuration for the domain for uWSGI, which I'm running in emperor mode:

[uwsgi] protocol = uwsgi max-requests = 5000 chmod-socket = 660 master = True vacuum = True enable-threads = True auto-procname = True procname-prefix = michael- chdir = /srv/www/mysite.com module = app callable = app socket = /tmp/mysite.com.sock 

3 Answers

Answers 1

This kind of stuff is the actual and probably main use case for Python Celery (http://www.celeryproject.org/). As a general rule, do not run long running jobs that are CPU-bound in the wsgi process. It's tricky, it's inefficient, and most important thing, it's more complicated than setting up an async task in a celery worker. If you want to just prototype you can set the broker to memory and not using an external server, or run a single threaded redis on the very same machine.

This way you can launch the task, call task.result() which is blocking, but it blocks in an IO-bound fashion, or even better you can just return immediately by retrieving the task_id and build a second endpoint /result?task_id=<task_id> that checks if result is available:

result = AsyncResult(task_id, app=app) if result.state == "SUCCESS":    return result.get() else:    return result.state  # or do something else depending on the state 

This way you have a non-blocking wsgi app that does what is best suited for: short time CPU-unbound calls that have IO calls at most with OS-level scheduling, then you can rely directly to the wsgi server workers|processes|threads or whatever you need to scale the API in whatever wsgi-server like uwsgi, gunicorn, etc. for the 99% of workloads as celery scales horizontally by increasing the number of worker processes.

Answers 2

This approach works for me, it calls the timeout command (sleep 10s) in the command line and lets it work in the background. It returns the response immediately.

@app.route('/endpoint1') def endpoint1():     subprocess.Popen('timeout 10', shell=True)     return 'success1' 

However, not testing on WSGI server, but just locally.

Answers 3

Since this works locally, but doesn't with NGINX and uWSGI ...

  • Have you tried adding processes = 2 and threads = 2 to your uWSGI config?
  • Have you tried running this without NGINX?
Read More

Saturday, August 25, 2018

uWSGI Emperor does not reload Vassal by touching the .ini file

Leave a Comment

I have multiple uWSGI vassals, all monitored by uwsgi emperor. I update the code for my app (Django) and I want the emperor to perform a clean reload of one of the vassals. To do that I

touch vassal-foo.ini 

In the logs I see [emperor] reload the uwsgi instance vassal-foo.ini. This sounds promising, but the app is not reloaded. It continues to run the old version. Checking the process (PID) startup time, indeed, it has not been restarted.

Any hints what might cause this? Few things that might be uncommon:

  • Neither the emperor nor the vassal run in master mode
  • Emperor was installed with pip and runs under initctl
  • kill -9-ing the vassal triggers a correct reload (obviously)
  • I use symlinks
  • I have a secondary thread inside my python app (threading.Thread(target).start()) running with daemon=True

Things I tried and did not work:

  • Run the process without any additional threads (remove threading.Thread(target).start())
  • Touching with touch --no-dereference vassal-foo.ini
  • Starting emperor with --emperor-nofollow

vassal-foo.ini:

master         = false processes      = 1 thunder-lock   = true enable-threads = true socket         = /tmp/%n.sock chmod-socket    = 666 vacuum          = true 

Emperor:

exec /tmp/uwsgi --emperor /tmp/configs/uwsgi/ --die-on-term --uid me --gid me --logto /tmp/logs/uwsgi-emperor.log 

uWSGI version

$ uwsgi --version 2.0.17 

0 Answers

Read More

Tuesday, January 23, 2018

Uwsgi disables django.request logging

Leave a Comment

If I start application using uwsgi I don't see logs related to django.requests.

But If I start the same code on the same machine using

manage.py runserver 8080 

it works perfectly.

Any ideas why it might happen?

I run uwsgi by this command

/home/gs/python-env/bin/uwsgi --ini /etc/uwsgi.d/uwsgi.ini --static-map /static=/home/gs/api/static/ 

uwsgi.ini

[uwsgi] http-socket=:8080 home=/home/gs/python-env chdir=/home/gs/api module=server.wsgi env=server.settings processes=1 enable-threads=true 

My logging configuration from settings.py

LOGGING = {     'version': 1,     'disable_existing_loggers': True,     'formatters': {         'verbose': {             'format': '%(levelname)s %(asctime)s %(process)d %(threadName)s %(module)s %(funcName)s %(message)s'         }     },     'handlers': {         'console': {             'class': 'logging.StreamHandler',         },         'file': {             'level': 'DEBUG',             'class': 'logging.handlers.RotatingFileHandler',             'filename': '/var/log/gs/api.log',             'formatter': 'verbose',             'maxBytes': 1024 * 1024 * 16,  # 16Mb         },         'elasticsearch': {             'level': 'DEBUG',             'class': 'api.common.elasticsearch_log_handler.ElasticSearchHandler',             'hosts': [{'host': cluster.ES_HOST, 'port': 443}],             'es_index_name': 'logstash',             'es_additional_fields': {'type': 'api', 'cluser': cluster.CLUSTER_NAME},             'auth_type': ElasticSearchHandler.AuthType.NO_AUTH,             'use_ssl': True,         }     },     'loggers': {        'django': {             'handlers': ['file', 'elasticsearch', 'console'],             'level': 'INFO',             'propagate': True         },         'django.request': {             'handlers': ['file', 'elasticsearch', 'console'],             'level': 'DEBUG',             'propagate':False          }     } } 

If I change info to debug for 'django' I will see my logs from django logger but not from django.request.

UPD: If I write my own middleware I can log requests. But I want to know why django.request doesn't work with uwsgi.

1 Answers

Answers 1

Django's runserver provides the log messages that show up under django.server. When not running under runserver there are still some messages that can be logged to django.request (mostly error messages) but the informational log message for each request only exists in runserver. I verified this by looking at the uWSGI and the Django source.

If you want a similar log message you can use django-request-logging.

Read More

Tuesday, April 4, 2017

uwsgi: *** no app loaded. going in full dynamic mode ***

Leave a Comment

wapp.py is in:

/var/www/KRAKEN/public/site.me/wapp 

with the structure:

|-- __init__.py |-- wapp.py |-- wapp.ini |-- mod_db |-- mod_form |-- multimedia |-- pip-selfcheck.json |-- pyvenv.cfg |-- requirements.txt |-- run_now.py |-- static `-- templates 

My wapp.ini which i run in emperor mode is:

[uwsgi] dir             = /var/www/KRAKEN/public/site.me chdir           = %(dir) master          = true processes       = 1 socket          = /run/uwsgi/wapp.sock chmod-socket    = 666 enable-threads  = true vacuum          = true virtualenv      = %(dir) binary-path     = %(dir)/bin/uwsgi wsgi-file       = wapp.py mount           = /%dir/wapp/app=wapp.py logto           = %(dir)/uwsgi.log 

Previously the app was on the website root /var/www/KRAKEN/public/site.me, but i dont know what's going on because i updated all the pertinent config parameters, but obviously i'm missing something. I can run the app with no errors, inside the virtual env with: python wapp.py

Any tips? Thanks!

1 Answers

Answers 1

I used my old config, changing just the virtualenv parameter and bin, worked. I bet i changed a lot of things too fast and one thing broke the other in a spiral of doom.

Read More

Thursday, May 5, 2016

Does uWSGI start all processes at boot time?

Leave a Comment

I have several apps running on uWSGI. Most of them grow in memory usage over time. I've always attributed this to a memory leak that I hadn't tracked down. But lately I've noticed that the growth is quite chunky. I'm wondering if each chunk correlates with a process being started.

Does uWSGI start all processes at boot time, or does it only start up a new one when there are enough requests coming in to make it necessary?

Here's an example config:

[uwsgi] strict = true  wsgi-file = foo.py callable = app  die-on-term = true  http-socket = :2345  master = true enable-threads = true thunder-lock = true processes = 6 threads = 1  memory-report = true 

update: this looks relevant: http://uwsgi-docs.readthedocs.org/en/latest/Cheaper.html

Does "worker" mean the same thing as "process" (answer seems to be yes)? If so then it seems like if I want the number to remain constant always, I should do:

cheaper = 6 cheaper-initial = 6 processes = 6 

1 Answers

Answers 1

Yes, uWSGI will start all processes (or workers - worker is an alias for process in uWSGI config) at boot time but it will depend on your application what will go from then. If application imports all modules at boot time, it should be fully loaded before first request, but if some modules are loaded on request time, each worker will be fully loaded only after first requests (assuming that any request will load all modules. If not, it will be fully loaded only after doing combination of requests that will load all of it).

But even after loading all modules, application memory usage won't be constant. There may be some logging, global variables, debug information etc accumulating on every request. If you're using any framework it is possible that it will save some data for debugging, statistics etc.

By default, cheaper is not enabled - that means uWSGI will spawn all workers at startup. If you want to use cheaper mode, you need to define at least cheaper parameter. More about usage of cheaper system you can find in documentation

There are many other systems built in uWSGI to control load based on requests amount. For example

If you're worried that uWSGI will take up too much resources, there are solutions for that too:

Read More