Django multi-threaded and mod_wsgi - django

First of all my site is up and running OK. There is no critical issues.
I want to understand a couple of things though.
I'll start with an overview of my system.
It's a django-powered site located on a CentOS 5.3 VPS with 256MB RAM, under apache with mod_wsgi.
The django application runs as a Daemon process with 1 threads.
What I need in my application is:
1. Initialize logging (currently it is working, but I get double logging every time)
2. Start to daemon threads to do some background work
Now, I have read and implemented the solution offered in
http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html
but it didn't help much.
Basically I had to manually disable worker MPM (only prefork MPM is running) and configure the daemon process to be with one process and one thread (for some reason it does not work with any other combination).
But what is weird is that the site is running and it is creating the 2 background threads.
1. How does that happen?
2. Does my settings mean that concurrent requests will not be handled on my site?
Here is some configuration from my site
httpd.conf
WSGIScriptAlias / /var/www/NiceHouse/trunk/apache/django.wsgi
WSGISocketPrefix run/wsgi
<VirtualHost *:80>
WSGIDaemonProcess site-1 user=**** group=**** threads=1
WSGIProcessGroup site-1
ServerName *****
ServerAlias *****
ServerAdmin *****
#DocumentRoot /usr/local/www/documents
#Alias /robots.txt /usr/local/www/documents/robots.txt
#Alias /favicon.ico /usr/local/www/documents/favicon.ico
Alias /media/ /usr/lib/python2.4/site-packages/django/contrib/admin/media/
Alias /site_media/ /var/www/NiceHouse/trunk/media/
Alias /phpmyadmin /var/www/phpmyadmin/
#<Directory /usr/local/www/documents>
#Order allow,deny
#Allow from all
#</Directory>
WSGIScriptAlias / /var/www/NiceHouse/trunk/apache/django.wsgi
#<Directory /usr/local/www/wsgi-scripts>
#Order allow,deny
#Allow from all
#</Directory>
</VirtualHost>
swtune.conf
<IfModule prefork.c>
StartServers 1
MinSpareServers 1
MaxSpareServers 3
ServerLimit 50
MaxClients 50
MaxRequestsPerChild 1000
</IfModule>
django.wsgi
import sys
import os
os.environ['PYTHON_EGG_CACHE']='/tmp/hoge'
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
sys.path.insert(0,'/var/www/NiceHouse/trunk')
import settings
import django.core.management
django.core.management.setup_environ(settings)
utility = django.core.management.ManagementUtility()
command = utility.fetch_command('runserver')
command.validate()
import django.conf
import django.utils
django.utils.translation.activate(django.conf.settings.LANGUAGE_CODE)
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
I'll appreciate any help
Thanks, Elad

You may be getting double logging for a number of reasons. First is where have you put the logging? If you have stuck logging in settings.py file, then it will get executed twice with that WSGI script file contents you are using. The blog post explains how settings file is imported twice.
BTW, you didn't even copy the WSGI script file correctly. That in the blog post does not set DJANGO_SETTINGS_MODULE environment variable.
You may also be seeing double logging if you yourself are importing a module with the logging in it via two different paths. That is, qualified and not qualified by site package name. From memory this problem is also mention in blog post.
In respect of background threads, although you have specified threads=1, mod_wsgi has a few separate threads of its own to make sure things are working correctly and kill off process if deemed it is dead locked.
BTW, you really should get worker MPM going if you aren't using mod_php. You are only going to waste memory by using prefork MPM.

Related

Django Apache2 VirtualEnv - no response from server

So I am trying to migrate my app to a new production server. I'm not getting a reply from the server Apache server when I access it. The server is on AWS and it's a standard Apache config with just one site enabled:
<VirtualHost *:80>
Alias /static/ /home/ubuntu/myapp/myapp/myapp/static
Alias /media/ /home/ubuntu/myapp/myapp/myapp/media
<Directory /home/ubuntu/myapp/myapp/myapp/static>
Require all granted
</Directory>
<Directory /home/ubuntu/myapp/myapp/myapp/media>
Require all granted
</Directory>
<Directory /home/ubuntu/myapp/myapp/myapp>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
WSGIDaemonProcess myapp python-home=/home/ubuntu/myapp/myapp/myapp python-path=/home/ubuntu/myapp:/home/ubuntu/myapp/lib/python3.6/site-packages
WSGIProcessGroup myapp
WSGIScriptAlias / /home/ubuntu/myapp/myapp/myapp/myapp/wsgi.py
ErrorLog /var/log/apache2/myapp_error.log
LogLevel warn
CustomLog /var/log/apache2/myapp_access.log combined
</VirtualHost>
I have made sure that all files are owned by the ubuntu user and that www-data has group rights.
The wsgi file is the original, but I added a print statement to see the folder it's checking for the application:
"""
WSGI config for match2 project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""
import os, sys
print(sys.path)
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
application = get_wsgi_application()
Eventually, the error log will produce:
Timeout when reading response headers from daemon process 'myapp': /home/ubuntu/myapp/myapp/myapp/myapp/wsgi.py
I'd appreciate any advice.
Timeout when reading response headers from daemon process 'myapp' means your application is taking to long to handle the request. This could be because it is deadlocked, or is waiting on backend service.
Add WSGIApplicationGroup to your virtual host configuration.
<VirtualHost *:80>
# config remaining parts
WSGIApplicationGroup %{GLOBAL}
# config remaining parts
</VirtualHost>
From docs
... forces the WSGI application to run in the main Python interpreter context of each process. This is preferred in this scenario as some third party packages for Python which include C extensions will not run in the Python sub interpreter contexts which mod_wsgi would use by default. By using the main Python interpreter context you eliminate the possibility of such third party packages for Python causing problems.
A similar case link.
Also:
Looking at this,
python-home=/home/ubuntu/myapp/myapp/myapp python-path=/home/ubuntu/myapp:/home/ubuntu/myapp/lib/python3.6/site-packages
I think you have the wrong path for python-home. Make sure python-home path is correctly provided. Activate your virtual environment and run the command to get the python-home path [docs].
python -c 'import sys; print(sys.prefix)'

How I can run /myapp/my_app.py by default when accessing `localhost` using Bottle?

Desired Behaviour
I want to serve content created by the file at:
/myapp/my_app.py
when accessing localhost.
Question
I know that if I add the following to test.py and run the file directly, the results will be accessible at localhost:8080:
from bottle import route, run
#route('/')
def hello():
return "Hello World!"
run(host='localhost', port=8080, debug=True)
But how do I trigger this file to run by default when accessing localhost?
Environment
Linux Mint 17
MongoDB
RockMongo (Apache2, PHP, MongoDB Driver)
What I've Tried
I installed mod_wsgi and created /var/www/html/myapp/app.wsgi with this content:
import bottle
import os
os.chdir(os.path.dirname(__file__))
#route('/')
def hello():
return "Hello World!"
application = bottle.default_app()
And then restarted Apache.
But going to localhost just shows a file directory.
I then created /etc/apache2/sites-enabled/mygreatapp.conf with this content:
<VirtualHost *>
ServerName google.com
WSGIScriptAlias / /var/www/html/myapp/app.wsgi
<Directory /var/www/html/myapp>
WSGIProcessGroup yourapp
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
But I still just see a file directory.
Official Instructions
http://bottlepy.org/docs/dev/deployment.html#apache-mod-wsgi
Further Information
Troubleshooting
See if mod_wsgi is loaded
apache2ctl -M
...
wsgi_module (shared)
Definitions
For my own reference, I'm trying to fully comprehend several elements that I think are involved in the process, feel free to correct if my understandings are wrong:
WSGI - A convention for how applications should communicate with servers.
It does not exist anywhere else other than as words in the PEP 3333 - Source
mod_wsgi - An Apache module that allows Python files to communicate with Apache.
Web Framework - See a list of them here: https://wiki.python.org/moin/WebFrameworks
Web Server - http://en.wikipedia.org/wiki/Web_server
Apache Server - http://en.wikipedia.org/wiki/Apache_HTTP_Server
I finally have "Hello World!" displaying in the browser at localhost.
I will paste the various required configs and files below.
I'm a newb so I don't know if this is definitive or best practise.
/var/www/html/myapp/app.wsgi
# view the effect of import method:
http://stackoverflow.com/a/2452639/1063287
import bottle
import os
os.chdir(os.path.dirname(__file__))
# note i am using bottle.route and not just route
#bottle.route('/')
def hello():
return "Hello World!"
application = bottle.default_app()
/etc/apache2/sites-available/000-default.conf (note: this is the default .conf file)
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
WSGIScriptAlias / /var/www/html/myapp/app.wsgi # just added this
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Viewing the Apache error log is what eventually led me to try a few different things:
sudo tail -100 /var/log/apache2/error.log
Where I saw things like:
Exception occurred processing WSGI script '/var/www/html/myapp/app.wsgi'.
Traceback (most recent call last):
File "/var/www/html/myapp/app.wsgi", line 8, in <module>
#route('/')
NameError: name 'route' is not defined
This was only after I had made the step of not using a new .conf file and just modifying the default one.
So for some reason it didn't like any new .conf files.

Apache/mod_wsgi daemon mode not working

I have problems getting mod_wsgi to run in daemon mode on my Debian/Apache/Python2.6/Django setup. In my virtual host config file I have
<VirtualHost *:80>
ServerName mysite.com
WSGIDaemonProcess mysite.com processes=2 threads=15
WSGIProcessGroup mysite.com
WSGIScriptAlias / /path/to/mysite/wsgi/django.wsgi
<Directory /path/to/mysite/wsgi/>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
set up. To test activation of daemon mode, I use this wsgi script:
import sys
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
def application(environ, start_response):
print >> sys.stderr, 'mod_wsgi.process_group = %s' % repr(environ['mod_wsgi.process_group'])
from django.core.handlers.wsgi import WSGIHandler
_application = WSGIHandler()
return _application(environ, start_response)
and the resulting log file always says:
mod_wsgi.process_group = ''
which, accroding to the documentation, indicates that daemon mode is not being used. I checked my setup multiple times, the versions of Apache, mod_wsgi and Python are matching and my setup is correct according to all the HOWTO's I've read out there. What could I be missing?
Edit: FYI my application is running fine in embedded mode, I just wanted to switch to daemon mode and found out it is not activated using the wsgi script above.
It turned out that a symlink wasn't set correctly so my config changes never loaded in Apache. Sorry for wasting your time, I thought I checked everything thoroughly before posting.
The line mod_wsgi.process_group = '' implies that you are still operating in embedded mode (as you note). mod_wsgi daemon mode will not work on Apache 1.x so I assume that you are running 2.x (as you also note).
You could try setting the apache
LogLevel info
so that there is more helpful information in the log file. I'm also assuming that you've forced apache to restart
# /etc/init.d/apache2 restart
this shouldn't be necessary in daemon mode so much, but if you were in embedded mode previously you will need to reload your config files.

I need help on configuring mod_wsgi and Django

Apache & mod_wsgi are configured correctly (I've created a hello
world .html apache file and a hello world mod_wsgi application with
no problems). I now need my Django app to work with my django.wsgi
file. What makes me think that it's not recognizing my wsgi file is that I
went into my django.wsgi file I created and completely deleted all of
the code in the file and restarted Apache and it still gives me the
same page (a listing of the files from Django app, not my actual
Django application. Configuring Apache and mod_wsgi went really well
but I'm at a loss of how to fix this. Here are some details:
Here is my current django.wsgi file:
import os
import sys
sys.path.append('/srv/www/duckling.org/store/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'store.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
I've tried a few different versions of the django.wsgi file
(including a version like the one over at http://www.djangoproject.com/).
This version of my wsgi is from here:
http://library.linode.com/frameworks/django-apache-mod-wsgi/ubuntu-10...
Also, here is my vhost apache configuration file below. I think these
are the main files that are suppose to do the job for me. Let me know if
you see any errors in what I'm doing and what else I might do to fix
this. The django app runs fine on the django's built-in development
server so I'm thinking it might have something with my paths.
No errors in my apache error.log file as well. It's acting as there's
no problem at all, which is not the case...the project isn't loading,
like I said just a listing of my files and directories of my Django
project. Here is my apache config file:
<VirtualHost 1.2.3.4:80>
ServerAdmin hi#duckling.org
ServerName duckling.org
ServerAlias www.duckling.org
DocumentRoot /srv/www/duckling.org/store/
<Directory /srv/www/duckling.org/store/>
Order Allow,Deny
Allow from all
</Directory>
Alias /static/ /srv/www/duckling.org/store/static/
<Directory /srv/www/duckling.org/store/static>
Order deny,allow
Allow from all
</Directory>
WSGIScriptAlias store/ /srv/www/duckling.org/store/wsgi-scripts/django.wsgi
<Directory /srv/www/wsgi-scripts>
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
And here are versions of the stack that I'm using, I saw over at the
mod_wsgi site that you all would like the versions of what I'm using
on the server:
Apache/2.2.14 (Ubuntu) PHP/5.3.2-1ubuntu4.5 with Suhosin-Patch
mod_python/3.3.1 Python/2.6.5 mod_wsgi/2.8
thanks,
j.
For a start, you should definitely not keep your Django files under your DocumentRoot. There's no need for them to be there, and it's a potential security risk - as you've seen, your current misconfiguration allows Apache to serve up your files directly: an attacker could guess that and download your settings.py, complete with your database password.
So, get rid of that DocumentRoot directive completely, as well as the first Directory section which allows direct access to /srv/www/duckling.org/store/. (You probably don't need the one serving up /srv/www/wsgi-scripts either.) That should make things a bit better.
By the way, this configuration will serve your website under duckling.org/store - is that what you want? If you want it under the root, you should just use:
WSGIScriptAlias / /srv/www/duckling.org/store/wsgi-scripts/django.wsgi

Django website on Apache with wsgi failing

I have a website I've built in django that I'm trying to get working on our corporate Apache server (on debian) for our intranet at my workplace. Unfortunately, Apache keeps returning server errors whenever I try to navigate to my site. Although I can navigate to the statics folder. My Apache config and wsgi script look like the following...
lbirdf.wsgi
import os
import sys
sys.path.append('/home/lbi/rdfweb/web')
sys.path.append('/home/lbi/rdfweb/web/lbirdf')
os.environ['DJANGO_SETTINGS_MODULE'] = 'lbirdf.settings_production'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Apache config
Listen 8080
<VirtualHost *:8080>
ServerName server1
WSGIScriptAlias /rdfweb /home/lbi/rdfweb/web/lbirdf/apache/lbirdf.wsgi
Alias /statics /home/lbi/rdfweb/web/lbirdf/statics
Alias /admin_media /home/lbi/rdfweb/web/lbirdf/admin_media
<Directory /home/lbi/rdfweb/web/lbirdf/apache>
Order allow,deny
Allow from all
</Directory>
<Directory /home/lbi/rdfweb/web/lbirdf/admin_media>
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Any ideas on where I might be going wrong?
What messages are in the Apache error log? Try setting DEBUG to true in Django settings file to get more informative error message sent back to browser in instance that it is an issue in your application.
Possible causes are, urls.py is wrong because you are erroneously including site prefix when you don't need to or a permissions issue because code running as Apache user and not you.
Not knowing the actual errors doesn't help in working out the problem.
Try:
sys.path.append('/home/lbi/rdfweb/')