Skip to content

Commit

Permalink
Serve application using gunicorn (#14)
Browse files Browse the repository at this point in the history
* Serve application using gunicorn

* cov
  • Loading branch information
ashwin1111 authored Feb 15, 2023
1 parent b1148fc commit bb49e3d
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[run]
omit = tests/*, ./venv/*, get-pip.py, fyle/*, fyle_partner_dashboard_api/*, *forms.py, *apps.py,*manage.py,*__init__.py,*migrations*,*asgi*,*wsgi*,*admin.py,*urls.py, *settings.py,
omit = tests/*, ./venv/*, get-pip.py, fyle/*, fyle_partner_dashboard_api/*, *forms.py, *apps.py,*manage.py,*__init__.py,*migrations*,*asgi*,*wsgi*,*admin.py,*urls.py, *settings.py, *gunicorn*,
2 changes: 1 addition & 1 deletion centralized_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ python manage.py migrate
python manage.py createcachetable --database cache_db

# Running development server
python manage.py runserver 0.0.0.0:8005
gunicorn -c gunicorn_config.py fyle_partner_dashboard_api.wsgi -b 0.0.0.0:8005
22 changes: 9 additions & 13 deletions fyle_partner_dashboard_api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
]

MIDDLEWARE = [
'request_logging.middleware.LoggingMiddleware',
'corsheaders.middleware.CorsMiddleware',
'fyle_partner_dashboard_api.logging_middleware.ErrorHandlerMiddleware',
'django.middleware.security.SecurityMiddleware',
Expand Down Expand Up @@ -147,30 +148,25 @@
'handlers': ['debug_logs'],
'level': 'ERROR',
'propagate': False
},
'gunicorn': {
'handlers': ['request_logs'],
'level': 'INFO',
'propagate': False
}
}
}

# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases

if os.environ.get('DATABASE_URL', ''):
# Defaulting django engine for qcluster
if len(sys.argv) > 0 and sys.argv[1] == 'qcluster':
DATABASES = {
'default': dj_database_url.config()
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'OPTIONS': {
'options': '-c search_path={0}'.format(os.environ.get('DB_SCHEMA'))
},
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
}
'default': dj_database_url.config(engine='django_db_geventpool.backends.postgresql_psycopg2')
}

CACHES = {
Expand Down
122 changes: 122 additions & 0 deletions gunicorn_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import os
from psycogreen.gevent import patch_psycopg

# https://docs.gunicorn.org/en/stable/settings.html

port_number = 8000
bind = '0.0.0.0:{0}'.format(port_number)
proc_name = 'fyle_partner_dashboard_api'

# The maximum number of pending connections.
backlog = int(os.environ.get('GUNICORN_BACKLOG', 2048))

# The number of worker processes for handling requests.
workers = int(os.environ.get('GUNICORN_NUMBER_WORKERS', 2))

# Workers silent for more than this many seconds are killed and restarted.
timeout = int(os.environ.get('GUNICORN_WORKER_TIMEOUT', 60))

# The number of seconds to wait for requests on a Keep-Alive connection.
keepalive = int(os.environ.get('GUNICORN_KEEPALIVE', 2))

# The maximum number of simultaneous clients.
worker_connections = int(os.environ.get('GUNICORN_WORKER_CONNECTIONS', 1000))

# The granularity of Error log outputs.
loglevel = os.environ.get('GUNICORN_LOG _LEVEL', 'debug')

# The type of workers to use.
worker_class = os.environ.get('GUNICORN_WORKER_CLASS', 'gevent')

# The number of worker threads for handling requests.
threads = int(os.environ.get('GUNICORN_NUMBER_WORKER_THREADS', 1))

# The maximum number of requests a worker will process before restarting.
max_requests = int(os.environ.get('GUNICORN_MAX_REQUESTS', 20))

# The jitter causes the restart per worker to be randomized by randint(0, max_requests_jitter).
max_requests_jitter = int(os.environ.get('GUNICORN_MAX_REQUESTS_JITTER', 20))

# Timeout for graceful workers restart.
graceful_timeout = int(os.environ.get('GUNICORN_WORKER_GRACEFUL_TIMEOUT', 5))

# Restart workers when code changes.
reload = True

# The maximum size of HTTP request line in bytes.
limit_request_line = 0

# Install a trace function that spews every line executed by the server.
spew = False

# Detaches the server from the controlling terminal and enters the background.
daemon = False

pidfile = None
umask = 0
user = None
group = None
tmp_upload_dir = None

errorlog = '-'
accesslog = '-'
access_log_format = '%({X-Real-IP}i)s - - - %(t)s "%(r)s" "%(f)s" "%(a)s" %({X-Request-Id}i)s %(L)s %(b)s %(s)s'


def post_fork(server, worker):
patch_psycopg()
server.log.info("Worker spawned (pid: %s)", worker.pid)


def pre_fork(server, worker): # noqa
pass


def pre_exec(server):
server.log.info("Forked child, re-executing.")


def when_ready(server):
server.log.info("Server is ready. Spawning workers")


def worker_int(worker):
worker.log.info("worker received INT or QUIT signal")

# get traceback info
import threading
import sys
import traceback
id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
code = []
for thread_id, stack in sys._current_frames().items():
code.append("\n# Thread: %s(%d)" % (id2name.get(thread_id, ""),
thread_id))
for filename, line_no, name, line in traceback.extract_stack(stack):
code.append('File: "%s", line %d, in %s' % (filename,
line_no, name))
if line:
code.append(" %s" % (line.strip()))
worker.log.debug("\n".join(code))


def worker_abort(worker):
worker.log.info("worker received SIGABRT signal")


def child_exit(server, worker):
server.log.info("server: child_exit is called")
worker.log.info("worker: child_exit is called")


def worker_exit(server, worker):
server.log.info("server: worker_exit is called")
worker.log.info("worker: worker_exit is called")


def nworkers_changed(server, new_value, old_value):
server.log.info("server: nworkers_changed is called with new_value: %s old_value: %s", new_value, old_value)


def on_exit(server):
server.log.info("server: on_exit is called")
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
dj-database-url==0.5.0
Django==3.1.14
django-db-geventpool==4.0.1
django-cors-headers==3.2.0
django-picklefield==3.0.1
django-q==1.3.3
Expand All @@ -8,6 +9,8 @@ django-rest-framework==0.1.0
djangorestframework==3.11.2
fyle==v0.29.0
fyle-rest-auth==1.2.0
gevent==22.10.2
gunicorn==20.1.0
psycopg2-binary==2.8.4
pylint==2.7.4
requests==2.25.0
Expand Down
2 changes: 1 addition & 1 deletion run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ python manage.py migrate
python manage.py createcachetable --database cache_db

# Running development server
python manage.py runserver 0.0.0.0:8000
gunicorn -c gunicorn_config.py fyle_partner_dashboard_api.wsgi -b 0.0.0.0:8000

0 comments on commit bb49e3d

Please sign in to comment.