Watch django server with gunicorn and daphne
first commit
14 files changed, +121 -0
+0-0__init__.py
No content changes (mode or rename only).
+0-0__pycache__/__init__.cpython-310.pyc
Binary file changed.
+0-0__pycache__/admin.cpython-310.pyc
Binary file changed.
+0-0__pycache__/apps.cpython-310.pyc
Binary file changed.
+0-0__pycache__/models.cpython-310.pyc
Binary file changed.
+3-0admin.py
| @@ -0,0 +1,3 @@ | ||
| 1 | +from django.contrib import admin | |
| 2 | + | |
| 3 | +# Register your models here. |
+6-0apps.py
| @@ -0,0 +1,6 @@ | ||
| 1 | +from django.apps import AppConfig | |
| 2 | + | |
| 3 | + | |
| 4 | +class SmartwatchConfig(AppConfig): | |
| 5 | + default_auto_field = 'django.db.models.BigAutoField' | |
| 6 | + name = 'smartwatch' |
+13-0management/commands/smartwatch.py
| @@ -0,0 +1,13 @@ | ||
| 1 | +from django.core.management.base import BaseCommand | |
| 2 | +from django.core.management import call_command | |
| 3 | +from smartwatch.watch import watch_files, start_servers | |
| 4 | + | |
| 5 | +class Command(BaseCommand): | |
| 6 | + help = 'Starts the file watcher' | |
| 7 | + | |
| 8 | + def handle(self, *args, **options): | |
| 9 | + self.stdout.write('Starting file watcher...') | |
| 10 | + call_command('collectstatic', '--noinput') | |
| 11 | + call_command('migrate') | |
| 12 | + start_servers() | |
| 13 | + watch_files() |
+0-0migrations/__init__.py
No content changes (mode or rename only).
+3-0models.py
| @@ -0,0 +1,3 @@ | ||
| 1 | +from django.db import models | |
| 2 | + | |
| 3 | +# Create your models here. |
+10-0settings.py
| @@ -0,0 +1,10 @@ | ||
| 1 | +from django.conf import settings | |
| 2 | + | |
| 3 | + | |
| 4 | +SMARTWATCH_HTTP_PORT = getattr(settings, 'SMARTWATCH_HTTP_PORT', 8000) | |
| 5 | +SMARTWATCH_HTTP_HOST = getattr(settings, 'SMARTWATCH_HTTP_HOST', '0.0.0.0') | |
| 6 | +SMARTWATCH_WS_PORT = getattr(settings, 'SMARTWATCH_WS_PORT', 8001) | |
| 7 | +SMARTWATCH_WS_HOST = getattr(settings, 'SMARTWATCH_WS_HOST', '0.0.0.0') | |
| 8 | + | |
| 9 | +SMARTWATCH_COLLECT_STATIC = getattr(settings, 'SMARTWATCH_COLLECT_STATIC', True) | |
| 10 | +SMARTWATCH_MIGRATE = getattr(settings, 'SMARTWATCH_MIGRATE', True) |
+3-0tests.py
| @@ -0,0 +1,3 @@ | ||
| 1 | +from django.test import TestCase | |
| 2 | + | |
| 3 | +# Create your tests here. |
+3-0views.py
| @@ -0,0 +1,3 @@ | ||
| 1 | +from django.shortcuts import render | |
| 2 | + | |
| 3 | +# Create your views here. |
+80-0watch.py
| @@ -0,0 +1,80 @@ | ||
| 1 | +import sys | |
| 2 | +import psutil | |
| 3 | +import logging | |
| 4 | +from watchdog.observers import Observer | |
| 5 | +from watchdog.events import FileSystemEventHandler | |
| 6 | +from django.core.management import call_command | |
| 7 | +from django.contrib.staticfiles import finders | |
| 8 | +import os | |
| 9 | +from multiprocessing import Process | |
| 10 | +from . import settings | |
| 11 | + | |
| 12 | +def get_project_name(): | |
| 13 | + settings_module = os.getenv('DJANGO_SETTINGS_MODULE') | |
| 14 | + if settings_module is not None: | |
| 15 | + project_name = settings_module.split('.')[0] | |
| 16 | + return project_name | |
| 17 | + else: | |
| 18 | + return None | |
| 19 | + | |
| 20 | +def kill_gunicorn(): | |
| 21 | + for process in psutil.process_iter(): | |
| 22 | + if 'gunicorn' in process.name(): | |
| 23 | + process.kill() | |
| 24 | + | |
| 25 | +def run_gunicorn_http(hostname=None, port=None): | |
| 26 | + hostname = hostname or settings.SMARTWATCH_HTTP_HOST | |
| 27 | + port = port or settings.SMARTWATCH_HTTP_PORT | |
| 28 | + kill_gunicorn() | |
| 29 | + os.system(f'gunicorn -b {hostname}:{port} {get_project_name()}.wsgi:application') | |
| 30 | + | |
| 31 | + | |
| 32 | +def kill_daphne(): | |
| 33 | + for process in psutil.process_iter(): | |
| 34 | + if 'daphne' in process.name(): | |
| 35 | + process.kill() | |
| 36 | + | |
| 37 | + | |
| 38 | +def run_daphne_ws(hostname=None, port=None): | |
| 39 | + hostname = hostname or settings.SMARTWATCH_WS_HOST | |
| 40 | + port = port or settings.SMARTWATCH_WS_PORT | |
| 41 | + kill_daphne() | |
| 42 | + os.system(f'daphne -b {hostname} -p {port} {get_project_name()}.asgi:application') | |
| 43 | + | |
| 44 | + | |
| 45 | +def start_servers(): | |
| 46 | + Process(target=run_gunicorn_http).start() | |
| 47 | + # Process(target=run_daphne_ws).start() | |
| 48 | + print('started the servers') | |
| 49 | + | |
| 50 | + | |
| 51 | +class ServerHandler(FileSystemEventHandler): | |
| 52 | + def on_modified(self, event): | |
| 53 | + should_restart = event.src_path.endswith('.py') | |
| 54 | + if event.src_path == 'requirements.txt': | |
| 55 | + logging.info(f'{event.src_path} has been modified. Installing requirements...') | |
| 56 | + should_restart = True | |
| 57 | + os.system('pip install -r requirements.txt') | |
| 58 | + if settings.SMARTWATCH_MIGRATE and 'migrations' in event.src_path: | |
| 59 | + should_restart = False | |
| 60 | + logging.info(f'{event.src_path} has been modified. Running migrations...') | |
| 61 | + call_command('migrate') | |
| 62 | + if settings.SMARTWATCH_COLLECT_STATIC and 'static' in event.src_path: | |
| 63 | + logging.info(f'{event.src_path} has been modified. Collecting static files...') | |
| 64 | + call_command('collectstatic', '--noinput') | |
| 65 | + if should_restart: | |
| 66 | + logging.info(f'{event.src_path} has been modified. Restarting server...') | |
| 67 | + start_servers() | |
| 68 | + | |
| 69 | + | |
| 70 | +def watch_files(): | |
| 71 | + server_handler = ServerHandler() | |
| 72 | + observer = Observer() | |
| 73 | + observer.schedule(server_handler, '.', recursive=True) | |
| 74 | + observer.start() | |
| 75 | + try: | |
| 76 | + while observer.is_alive(): | |
| 77 | + observer.join(1) | |
| 78 | + finally: | |
| 79 | + observer.stop() | |
| 80 | + observer.join() |