0

Below are the nginx.conf and gunicorn.start.sh files that I use for the Django application that I'm running (which, by the way, I didn't write).

When I make any one-time change to dynamic content, then repeatedly refresh the browser, the rendered content switches/flaps variously between PRE and POST changes made. But it should just update once, and never again.

  • The only thing that momentarily fixes the issue is restarting gunicorn:

    myapp$ sudo supervisorctl restart gunicorn

    But this only works until the next change to dynamic content. No good.

  • I've tried numerous browsers, and it happens even when I clear their caches. Makes no difference.

  • I also temporarily tried uWSGI instead of gunicorn (just to see), and the same issue occurs.
  • A tail -f gunicorn.access.log during browser refreshes shows HTTP statuses that vary between 200 (content was downloaded) and 304 (you already have the content; redirecting you to your local cache). But dynamic content shouldn't be cached.
  • Note that when running the application using the development server, like this:

    myapp$ python manage.py runserver --settings live 0.0.0.0:8080

    the issue doesn't occur; but neither does this use nginx nor gunicorn.

Any ideas?

I've tried everything I know, but don't know what is causing this flapping on dynamic content.

I don't see anything below that would cause this re-rendering of before/after dynamic content change (i.e. caching).

Thank you in advance!


#! /bin/bash
#
set -ue
#
# ==========================================================================
# -- The Django myapp Application UNIX HOME accunt location.
# -- The Django myapp Application location.
# ==========================================================================
export HOME="/home/myapp/"
export MYAPP_HOME="${HOME}/MYAPP/"
cd ${MYAPP_HOME} # The CWD *must* be this when this is launched!
# ==========================================================================


# ==========================================================================
# Gunicorn binary to run. A particular Gunicorn version is needed for this
# APP, so we pip(1m) installed it into its Python-2 virtual environment.
# ==========================================================================
GUNICORN="${HOME}/.virtualenvs/myapp/bin/gunicorn"
# ==========================================================================


# ==========================================================================
# -- Gunicorn PID-file, ACCESS-log and ERROR-log locations.
# -- Where to BIND Gunicorn to. We're using a UNIX DOMAIN (not TCP) SOCKET. 
# ==========================================================================
ACCESS_LOG="${MYAPP_HOME}/ROOTFS.d/var/log/gunicorn.access.log"
ERROR_LOG="${MYAPP_HOME}/ROOTFS.d/var/log/gunicorn.error.log"
PID_FILE="${MYAPP_HOME}/ROOTFS.d/var/run/gunicorn.pid"
#
BIND="unix:/var/run/myapp.d/myapp.sock" # Communicate with nginx via socket.
# ==========================================================================
# IMPORTANT: gunicorn only serves up dynamic content; not static or CSS content.
#            The nginx part of the stack is needed for the static content.
# https://stackoverflow.com/questions/20175243/django-gunicorn-not-load-static-files
# ==========================================================================


# ==========================================================================
# Gunicorn performance tunable parameters.
# ==========================================================================
NUM_WORKERS=3     # Number of worker processes.
MAX_REQUESTS=1000 # Number or requests to serve.
# ==========================================================================


# ==========================================================================
# -- WSGI Python module that starts the process.
# -- Name of the application.
# ==========================================================================
DJANGO_SETTINGS_MODULE='live' # ./live.py (Our settings file.).
DJANGO_WSGI_MODULE="wsgi"
NAME="myapp"
# ==========================================================================


# ==========================================================================
# Launch the WSGI Application Web Service.
# ==========================================================================
echo "gunicorn(1) starting with DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE}"
# ==========================================================================
exec $GUNICORN ${DJANGO_WSGI_MODULE}:application \
  --env DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
  --name $NAME \
  --workers $NUM_WORKERS \
  --max-requests $MAX_REQUESTS \
  --bind $BIND \
  --access-logfile ${ACCESS_LOG} \
  --error-logfile ${ERROR_LOG} \
  --pid ${PID_FILE} \
  --user myapp 
# ==========================================================================

upstream myapp_server {
    server unix:/var/run/myapp.d/myapp.sock fail_timeout=0;
    # =============================================================
    # Path to DYNAMIC (NOT STATIC) content (when using GUNICORN).
    # =============================================================
}

# When no server names match then crash out.
server {
   return 404;
}

server {
    listen 80;
    server_name example.com 103.11.65.155;
    return 301 https://example.com$request_uri; # Rewrites HTTP to HTTPS
    #rewrite ^ https://example.com permanent;
}

server {
    # ==========================================================================
    listen 443 ssl; # managed by Certbot
    server_name example.com 103.11.65.155;
    keepalive_timeout 25s;
    client_max_body_size 5M;

    root /home/myapp/MYAPP/;
    # ==========================================================================
    # Path used for the static-files location-block below.
    # NOT for the dynamic-content location-block below.
    # ==========================================================================

    # ==========================================================================
    # SSL Certificate for 'example.com' (not for 'www.example.com').
    # ==========================================================================
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    # ==========================================================================

    # ==========================================================================
    access_log /home/myapp/MYAPP/ROOTFS.d/var/log/nginx.access.log;
    error_log  /home/myapp/MYAPP/ROOTFS.d/var/log/nginx.error.log;
    # ==========================================================================

    # ==========================================================================
    # Location block for STATIC FILES ...
    # ==========================================================================
    # The string in between /xyx/ must be the same as the value for
    # settings.STATIC_URL (in settings.py). Typically this is '/static/', but
    # for MYAPP's it is '/m/'. We redundantly define one for '/static/'
    # too, just in case there's a hidden dependency on that traditional path.
    # ==========================================================================
    location /m/ {
        alias /home/myapp/MYAPP/static/;
        autoindex on;
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public";
        access_log off;
    }
    location /static/ {
        alias /home/myapp/MYAPP/static/;
        autoindex on;
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public";
        access_log off;
    }
    # ==========================================================================

    # ==========================================================================
    # Location block for DYNAMIC CONTENT served by GUNICORN ...
    # ==========================================================================
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://myapp_server;
        proxy_buffering off;
    }
    # ==========================================================================
}


server {
    # =========================================================
    # Redirect to WWW --to--> Non-WWW.
    # =========================================================
    listen 80;
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
    # =========================================================

    # ==========================================================================
    # SSL Certificate for 'www.example.com' (not for 'example.com').
    # ==========================================================================
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    # ==========================================================================
}
NYCeyes
  • 5,215
  • 6
  • 57
  • 64
  • The problem is not in your server configuration, but in your Django code. Somewhere you have made a query at module or class level, rather than inside a function. You should show the code for the page where you are seeing this. – Daniel Roseman Oct 15 '17 at 21:14
  • Thanks. I didn't write the code. It is Askbot code, and I'm using the latest in their github repository; though even the pip installable version v0.10.2 exhibits this issue, too. Note that I've never seen a complaint about this in the v0.7.x series, which is widely used. So if it's a bug (not sure it is), it must be new. – NYCeyes Oct 15 '17 at 21:22
  • Also, as noted, the issue doesn't appear when run under the development server. – NYCeyes Oct 15 '17 at 21:40

0 Answers0