Gunicorn reload not detecting changes in application code - python

I have seen that gunicorn reload uses inotify (when installed, which I have). I have verified that the reloader is working, and that some file changes are detected (mainly, changes to gunicorn itself)
But my application code is not included in the list of files being supervised by inotify.
What can I do for gunicorn to supervise my application code?
My application is a django app, with the following wsgi.py:
"""
WSGI config for my project.
This module contains the WSGI application used by Django's development server
and any production WSGI deployments. It should expose a module-level variable
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
this application via the ``WSGI_APPLICATION`` setting.
Usually you will have the standard Django WSGI application here, but it also
might make sense to replace the whole Django WSGI application with a custom one
that later delegates to the Django one. For example, you could introduce WSGI
middleware here, or combine a Django application with an application of another
framework.
"""
import os
import sys
from django.core.wsgi import get_wsgi_application
# This allows easy placement of apps within the interior
# core directory.
app_path = os.path.abspath(os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.pardir))
sys.path.append(os.path.join(app_path, 'core'))
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
# if running multiple sites in the same mod_wsgi process. To fix this, use
# mod_wsgi daemon mode with each site in its own daemon process, or use
# os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
application = get_wsgi_application()
# Apply WSGI middleware here.
# from helloworld.wsgi import HelloWorldApplication
# application = HelloWorldApplication(application)

Related

Deploying a Django Application (Apache, Passenger, Virtualenv)

Im stuck in deploying my working Django Application on a production PLESK server.
The project can be started as a development server successfully by typing:
httpdocs# cd mysite
httpdocs/mysite# source myvenv/bin/activate
httpdocs/mysite# export LD_LIBRARY_PATH="/usr/local/lib"
httpdocs/mysite# python manage.py runserver <freyt.de>:8000
Then, if I point the browser to freyt.de:8000 I can see my app. Fine.
Right now, I'm trying to call my app by Passenger from Apache. When checking with "passenger-config restart-app" it seems to run, but when curl freyt.de it shows me html with 403 Forbidden. So, I assume my Django app is not started successfully.
This is my current folder structure:
I already adjusted some topics in PLESK as follows:
Apache Webserver: wsgi is activated
I created a Service Plan and subscribed it with my domain freyt.de
In the Service Plan under tab "Webserver" I added additional directives for HTTP as follows.
PassengerEnabled On
PassengerAppType wsgi
PassengerStartupFile passenger_wsgi.py
In the Service Plan under "Hosting Parameters" I enabled SSH access to the server shell: /bin/bash
For the "Domain" I set the Document root to "..httpdocs/public". Also I added in "Apache & nginx Settings" the same directives. (I also tried without, but dont seem to have an effect.)
Some details at Document Root:
I added .htaccess in public with again same directives (just for testing). No other files in public.
My passenger_wsgi.py contains, which seems to be ok:
import sys, os
cwd = os.getcwd()
sys.path.append(cwd)
sys.path.append(cwd + '/mysite')
if sys.version < "2.7.9":
os.execl(cwd + "/mysite/myvenv/bin/python", "python3.6", *sys.argv)
sys.path.insert(0, cwd + '/mysite/myvenv/bin')
sys.path.insert(0, cwd + '/mysite/myvenv/lib/python3.6')
#sys.path.insert(0, cwd + '/mysite/myvenv/lib/python3.6/site-packages/django')
sys.path.insert(0, cwd + '/mysite/myvenv/lib/python3.6/site-packages')
os.environ['DJANGO_SETTINGS_MODULE'] = "mysite.settings"
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
The file mysite/mysite/wsgi.py is untouched:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_wsgi_application()
Would be great, if someone could point me in the correct direction. I think its just a small mistake somewhere :-) Thanks in advance.

How to deploy Django/React/Webpack app on Digital Ocean through Passenger/Nginx

I'm trying to deploy a web app built with Django/Redux/React/Webpack on a Digital Ocean droplet. I'm using Phusion Passenger and Nginx on the deployment server.
I used create-react-app to build a Django app which has a frontend that uses React/Redux, and a backend api that uses django-rest-framework. I built the frontend using npm run build.
The Django app is configured to look in the frontend/build folder for its files and everything works as expected, including authentication. It's based on this tutorial: http://v1k45.com/blog/modern-django-part-1-setting-up-django-and-react/
In settings.py:
ALLOWED_HOSTS = ['*']
TEMPLATES = [
...
'DIRS': [
os.path.join(BASE_DIR, 'frontend/build'),
],
...
]
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'frontend/build/static'),
]
On my development machine, I activate a Python 3.6 virtual environment and run ./manage.py runserver, and the app is displayed at localhost:3000.
On the deployment server, I've cloned the files into a folder in var/www/ and built the frontend.
I've set up Passenger according to the docs with a file passenger_wsgi.py:
import myapp.wsgi
application = myapp.wsgi.application
And the wsgi.py file is in the djangoapp folder below:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
application = get_wsgi_application()
The Passenger docs only cover a single-part app:
https://www.phusionpassenger.com/library/walkthroughs/start/python.html
https://www.phusionpassenger.com/library/walkthroughs/deploy/python/digital_ocean/nginx/oss/xenial/deploy_app.html
https://www.phusionpassenger.com/library/deploy/wsgi_spec.html
I've tried cloning the tutorial part 1 code directly onto my server and following the instructions to run it. I got this to work on the server by adding "proxy": "http://localhost:8000" to frontend/package.json. If I run the Django server with ./manage.py runserver --settings=ponynote.production_settings xxx.x.x.x:8000
then the app is correctly served up at myserver:8000. However Passenger is still not serving up the right files.
I have changed wsgi.py to say this:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.production_settings")
application = get_wsgi_application()
The page served by Passenger at URL root now appears to have the right links to the js files such as "text/javascript" src="/static/bundles/js/main.a416835a.js, but the links don't work: the expected js is not present. Passenger is failing to serve the js files from static/bundles/js, even though the Django server can find them.
Very grateful for any help or ideas.
Create-react-app has a fairly opinionated setup for local and production environments.
Locally, running npm start will run a webpack-dev-server, which you would typically access on port 3000. It runs a local nodejs web server to serve the files. You can route requests to your local Django server via the proxy setting.
It's worth noting that at this point there is little or no connection between your React app and Django. If you use the proxy setting, the only thing connecting the two apps is the routing of any requests not handled by your React app to your Django app via the port.
By default in create-react-app (and as noted in the tutorial you mentioned you are following) in production you would run npm run build which will process your create-react-app files into static JS and CSS files, which are then accessed in Django like static files any other Django app.
One thing Django is missing in order to access the static files is a way to know what files are generated when running npm run build. Running a build will typically result in files output like this:
- css
|- main.e0c3cfcb.css
|- main.e0c3cfcb.css.map
- js
|- 0.eb5a2873.chunk.js
|- 0.eb5a2873.chunk.js.map
|- 1.951bae33.chunk.js
|- 1.951bae33.chunk.js.map
A random hash is added to filenames to ensure cache busting. This is where webpack-bundle-tracker and django-webpack-loader come in. When build files are generated, an accompanying file is also created called manifest.json, listing the files created for the build. This is generated in Webpack and picked up by django-webpack-loader so that Django can know which files to import.
It is possible to run a nodejs server in production, or to use server-side rendering, but if you're following the tutorial you mentioned and using create-react-app default settings, then running npm run build and deploying the static files is the simplest, safest option.
Nothing in any of the Passenger deployment links you mention cover anything beyond deploying a Python/Django app - you would need to manage two apps and deployments to have both Django and React running as servers in production.
Note that the tutorial you mention covers how to get your build files into Django in production, but you will need to ensure that you have webpack-bundle-tracker, django-webpack-loader and your Django staticfiles configuration all configured to work together.
The key missing setting was the 'location' setting in the Passenger config file.
Although the Django server serves up the static files, including the build files for your React app, Nginx doesn't see any static files except those in a 'public' directory.
So to deploy a Django app built with Webpack to production, you need to tell Nginx about those files. If you're using Passenger, these settings are probably in a separate Passenger config file. 'alias' is the command to use in this case where the folder has a different name from 'static' (which is where the web page links point).
If you use a virtual environment for your app, you need to specify where Passenger can find the right Python executable.
/etc/nginx/sites-enabled/myapp.conf
server {
listen 80;
server_name xx.xx.xx.xx;
# Tell Passenger where the Python executable is
passenger_python /var/www/myapp/venv36/bin/python3.6;
# Tell Nginx and Passenger where your app's 'public' directory is
# And where to find wsgi.py file
root /var/www/myapp/myapp/myapp;
# Tell Nginx where Webpack puts the bundle folder
location /static/ {
autoindex on;
alias /var/www/myapp/myapp/assets/;
}
# Turn on Passenger
passenger_enabled on;
}
Passenger uses the wsgi.py file as an entry point to your app. You need a passenger_wsgi.py file one level above the wsgi.py file. This tells Passenger where to find the wsgi.py file.
/var/www/myapp/myapp/passenger_wsgi.py
import myapp.wsgi
application = myapp.wsgi.application
/var/www/myapp/myapp/myapp/wsgi.py
If you are using a separate production_settings.py file, make sure this is specified here.
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.production_settings")
application = get_wsgi_application()

How do I disable whitenoise for local development of my Django project?

I've set up a Django project deployed on Heroku using the Heroku Django project template. Heroku's template uses whitenoise to collect static files in a /static/ directory located on my project root.
This is great for my production environment; Heroku runs "manage.py collectstatic" each time I push new files to my server. However, it's a pain when developing locally: every time I change my static files (e.g., css), I have to manually run "python manage.py collectstatic" before seeing changes on my development server.
Is there an easy way to disable whitenoise on my local machine so that I don't have to run "python manage.py collectstatic" every time I want to see changes to local static files?
I've tried creating a separate "development_settings.py" file and removing all references to whitenoise in that file, but it doesn't work because whitenoise is still referenced in wsgi.py, which causes errors.
WhiteNoise has a setting called WHITENOISE_AUTOREFRESH for exactly this reason.
From the WhiteNoise Docs:
WHITENOISE_AUTOREFRESH: Rechecks the filesystem to see if any files have changed before responding. This is designed to be used in development where it can be convenient to pick up changes to static files without restarting the server. For both performance and security reasons, this setting should not be used in production.
The default setting of this is the value of settings.DEBUG so it should be on by default if you're running a development server.
It looks like the default Heroku template specifies an old version of WhiteNoise. If you run
pip install --upgrade whitenoise
you should find it automatically picks up changes to your static files when in development (i.e. when settings.DEBUG is True).
Although I didn't find an easy way to disable whitenoise on my development server, I did find a convenient workaround for making this whole process easier:
Add a new command alias to your .bash_profile file (or bin/activate if you are using a virtual environment for development) that both runs collectstatic and launches a server at the same time:
alias launch='python manage.py collectstatic --noinput; foreman start'
The current version of whitenoise will pick up changes in your static files automatically. But it can slow down the startup of runserver quite a bit, as it will iterate over all static files. I fixed this by disabling whitenoise in runserver. Now my wsgi.py looks like this:
import os
import sys
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "...")
application = get_wsgi_application()
# guess whether this is a runserver invocation with staticfiles
has_staticfiles = False
if 'runserver' in sys.argv:
from django.conf import settings
import inspect
if settings.DEBUG:
has_staticfiles = any(
"django/contrib/staticfiles/management/commands/runserver"
in x[1]
for x in inspect.stack())
if has_staticfiles:
print('runserver with staticfiles detected, skipping whitenoise')
else:
# Do not use whitenoise with runserver, as it's slow
from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)

How do I configure the name of my WSGI application on AWS Elastic Beanstalk?

My Python web application is called app
# example.py
import flask
app = flask.Flask(__name__.split('.')[0])
and when I attempt to launch it on AWS-EB using
# run.py (set correctly with WSGIPath)
from example import app
if __name__ == "__main__":
app.run()
I get
mod_wsgi (pid=22473): Target WSGI script '/opt/python/current/app/run.py'
does not contain WSGI application 'application'.
How to I tell AWS that my application instance is called app?
mod_wsgi expects variable called application. Try to do something like this
from example import app as application
Note: don't do application.run(). It is not needed.
While the WSGIPath can be configured. Beanstalk still expects the app variable to be named as 'application'.
A simple workaround for small single file python apps can be
from flask import Flask
app = Flask(__name__)
application = app # For beanstalk
You can keep the rest of the code as is. You just need to add that single line application = app

How to setup python-pulsar with apache

Trying to work with Django python pulsar concurrent processing framework.
The wsgi server provided by pulsar can be used through command line as
$python manage.py pulse
which basically starts a HTTP WSGI server, similar to django's dev server.
How can it be set up with Apache webserver with mod_wsgi?
Is this case what you really want is to use pulsar's WSGI server and consume your django app as a regular wsgi application (if you are on django 1.5.x or above it would have created a wsgi.py in your project home). Here's an example:
from pulsar.apps import wsgi
import yourapp
middlewares = [
wsgi.middleware.wait_for_body_middleware,
yourapp.wsgi.application
]
if __name__ == '__main__':
wsgi.WSGIServer(wsgi.handlers.WsgiHandler(middleware=middlewares)).start()
protip: the "wait_for_body_middleware" makes pulsar wait for the full body response to be available before moving on to another request (which is the normal behavior of most webapps)
source:
http://pythonhosted.org/pulsar/apps/wsgi/intro.html#wsgi-server

Categories

Resources