Hi all,
I have this weird problem: REST API response is not returned to callers
correctly. It can only be recreated under some situation. Maybe it is a
caching problem, or incorrect configurations, or bug somewhere (???)
The configuration is Nginx<->uWsgi<->Django Rest Framework (DRF) under
Ubuntu.
I will summarize the business logic and the problem:
=========================================
All REST APIs are protected by Basic Authentication (username/password info
is persisted in Postgres)
DRF gets the authentication header and does the authentication itself.
There is a POST REST API "login" ; it returns a response with the user
information (like username).
There are other REST APIs, and say one of them is POST API called "XXX".
To recreate the problem:
====================
Client(the tool Postman) calls "login" API with user "A" authentication.
Response is good with user "A" info; response is 200 (as expected)
Client calls "XXX" API with user "B". It returns 500 (as expected).
Client calls "login" again repeatedly with user "A" authentication; now we
see intermittent problem; sometimes the returned response is about user
"A", but sometimes it is about user "B". Correct answer should be always
about user "A". All responses are 200.
My investigation:
==============
When the problem happens, if I look at the Nginx logs, I can see the new
entries with response status 200 but when I look at the Django logs, I
don't see the new entries. Based on this observation, I think Django is
being skipped somehow. Maybe uWsgi is being skipped as well. Maybe Nginx is
caching some response for certain situation. But it seems all is triggered
by the 500 response.
Any debugging tips is appreciated. I am just looking for new idea on how to
approach the problem.
Thanks in advance.
Steve
Below is configuration details:
========================
Ubuntu 16.04 LTS
uWSGI (2.0.14)
Django (1.9.12)
djangorestframework (3.3.3)
nginx version: nginx/1.10.0 (Ubuntu)
===========nginx.conf====================
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
log_format auth
'http_authorization= "$http_authorization" '
'request= "$request" '
'time_local= "$time_local" '
'status= "$status" '
;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
============nginx default file===================
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
try_files $uri $uri/ /index.html;
}
}
============nginx config file for django================
# the upstream component nginx needs to connect to
upstream django {
# we will be using socket connection
server unix:///tmp/zlims_uwsgi.sock;
}
# configuration of the server
server {
# use this version to receive all requests
listen 8000 default_server;
# the domain name it will serve for
# server_name _;
charset utf-8;
# server root, any location block path will be relative to this root
root /opt/zlims;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
#alias /opt/zlims/media; # your Django project's media files -
amend as required
}
location /static {
alias /opt/zlims/be/static/; # your Django project's static files -
amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
#include /opt/zlims/uwsgi_params; # the uwsgi_params file you
installed
include uwsgi_params; # the uwsgi_params file you installed
proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;
proxy_no_cache $cookie_nocache $arg_nocache$arg_comment;
proxy_no_cache $http_pragma $http_authorization;
access_log /var/log/nginx/auth.log auth;
}
}
========= uwsgi_params file======================
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
=============uwsgi vassel .ini file=====================
[uwsgi]
set-placeholder = base_dir = /opt/zlims/be
chdir =/opt/zlims/be
module =zlims.wsgi
home =/opt/zlims/venv
master =true
processes =10
socket =/tmp/%n.sock
chmod-socket =666
vacuum =true
daemonize =/var/log/zlims/uwsgi_zlims.log
logdate =%%d/%%m/%%Y %%T
log-maxsize =10000000
disable-logging =true # disable request logging
lazy-apps =true
single-interpreter =true
enable-threads =true
========uwsgi service script (for systemd) ===========================
# uwsgi service script
[Unit]
Description=uWSGI Emperor service
After=syslog.target
[Service]
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals/
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
_______________________________________________
uWSGI mailing list
[email protected]
http://lists.unbit.it/cgi-bin/mailman/listinfo/uwsgi