From 6a44ef30a3a4fc343724c89ea698a0fb46cc779a Mon Sep 17 00:00:00 2001 From: badbl0cks <4161747+badbl0cks@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:10:46 -0700 Subject: [PATCH] build fixes and static files fix, closes #28 --- Dockerfile | 20 +++----- deploy.sh | 2 +- django_project/middleware.py | 23 ++++----- django_project/settings.py | 47 ++++++++++++++++-- django_project/urls.py | 1 - django_project/wsgi.py | 1 + docker-compose_entire_app.yml | 2 +- fly.toml | 12 ++++- home/urls.py | 4 +- home/views.py | 9 +++- scripts/reset-db_make-migrations_seed-data.sh | 3 ++ {theme/static => static}/css/base.css | 0 .../css/card-multiselect.css | 0 {theme/static => static}/css/choices.min.css | 0 .../static => static}/css/hovercards.min.css | 0 {theme/static => static}/images/favicon.ico | Bin .../js/alpinejs.collapse@3.14.8.min.js | 0 .../js/alpinejs@3.14.8.min.js | 0 {theme/static => static}/js/base.js | 0 .../static => static}/js/card-multiselect.js | 0 {theme/static => static}/js/choices.min.js | 0 .../js/floating-ui_core@1.6.9.9.min.js | 0 .../js/floating-ui_dom@1.6.13.13.min.js | 0 {theme/static => static}/js/hovercards.min.js | 0 {theme/static => static}/js/tooltip.js | 0 theme/templatetags/trade_acceptance.html | 6 +-- 26 files changed, 91 insertions(+), 39 deletions(-) rename {theme/static => static}/css/base.css (100%) rename {theme/static => static}/css/card-multiselect.css (100%) rename {theme/static => static}/css/choices.min.css (100%) rename {theme/static => static}/css/hovercards.min.css (100%) rename {theme/static => static}/images/favicon.ico (100%) rename {theme/static => static}/js/alpinejs.collapse@3.14.8.min.js (100%) rename {theme/static => static}/js/alpinejs@3.14.8.min.js (100%) rename {theme/static => static}/js/base.js (100%) rename {theme/static => static}/js/card-multiselect.js (100%) rename {theme/static => static}/js/choices.min.js (100%) rename {theme/static => static}/js/floating-ui_core@1.6.9.9.min.js (100%) rename {theme/static => static}/js/floating-ui_dom@1.6.13.13.min.js (100%) rename {theme/static => static}/js/hovercards.min.js (100%) rename {theme/static => static}/js/tooltip.js (100%) diff --git a/Dockerfile b/Dockerfile index 9b0aabc..937ced3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,12 @@ -# Pull base image FROM python:3.12.2-bookworm -# Set environment variables (we want to write bytecode as we have multiple workers, so omit PYTHONDONTWRITEBYTECODE) +# (we want to write bytecode as we have multiple workers, so omit PYTHONDONTWRITEBYTECODE) ENV PYTHONUNBUFFERED 1 +ENV HOME /code -# Create and set work directory called `app` RUN mkdir -p /code WORKDIR /code -# Install dependencies COPY requirements.txt /tmp/requirements.txt RUN set -ex && \ @@ -16,20 +14,16 @@ RUN set -ex && \ pip install -r /tmp/requirements.txt && \ rm -rf /root/.cache/ -# Copy local project -COPY . /code/ -COPY .env.production /code/.env -ENV HOME=/code - RUN apt-get update && apt-get install -y nodejs npm xvfb netcat-openbsd nano curl -# Install playwright (via pip and install script) RUN playwright install-deps && playwright install -# Expose port 8000 +COPY . /code/ +COPY .env.production /code/.env + EXPOSE 8000 HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1 -# Use gunicorn on port 8000 -CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--workers", "4", "--worker-tmp-dir", "/dev/shm", "--timeout", "90"] +#CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--workers", "3", "--worker-class", "gevent", "--worker-connections", "1000", "--worker-tmp-dir", "/dev/shm", "--timeout", "90"] +CMD ["granian", "--interface", "wsgi", "django_project.wsgi", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"] diff --git a/deploy.sh b/deploy.sh index 2cfa5cf..1f2660d 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,4 +1,4 @@ #!/bin/bash python manage.py migrate --noinput python manage.py clear_cache -python manage.py collectstatic --noinput \ No newline at end of file +python manage.py collectstatic -c --no-input \ No newline at end of file diff --git a/django_project/middleware.py b/django_project/middleware.py index ac93aa2..34c6cc5 100644 --- a/django_project/middleware.py +++ b/django_project/middleware.py @@ -1,19 +1,18 @@ from django.conf import settings from django.contrib.auth import login -from accounts.models import CustomUser -from django.contrib.auth.models import User -class AutoLoginMiddleware: - """ - In development, automatically logs in as a predefined user if the request is anonymous. - """ +import time +import logging +class LogRequestsMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): - # Only perform auto-login if in DEBUG mode and user is not authenticated. - if settings.DEBUG and not request.user.is_authenticated and request.host in ['pocket-trade.fly.dev', 'localhost', '127.0.0.1']: - user = CustomUser.objects.get(email='rob@badblocks.email') - login(request, user, backend='django.contrib.auth.backends.ModelBackend') - + start = time.perf_counter() response = self.get_response(request) - return response \ No newline at end of file + end = time.perf_counter() + self.log(request, response, start, end) + return response + + def log(self, request, response, start, end): + logging.info(f"{request.method} {request.path_info} -> {response.status_code}, took {end - start}s") + diff --git a/django_project/settings.py b/django_project/settings.py index eb2cfad..8b46e19 100644 --- a/django_project/settings.py +++ b/django_project/settings.py @@ -2,11 +2,48 @@ import socket from pathlib import Path import environ import os +import logging +import sys env = environ.Env( DEBUG=(bool, False) ) +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + }, + }, + 'handlers': { + 'console': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + 'stream': sys.stdout, + 'formatter': 'verbose', + 'filters': [], + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console'], + 'level': 'INFO', + }, + 'django.server': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': False, + }, + '': { + 'handlers': ['console'], + 'level': 'INFO', + 'propagate': True, + }, + }, +} + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -80,10 +117,12 @@ MIDDLEWARE = [ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "allauth.account.middleware.AccountMiddleware", # django-allauth + "django_project.middleware.LogRequestsMiddleware", ] if DEBUG: - MIDDLEWARE.append("django_browser_reload.middleware.BrowserReloadMiddleware") + MIDDLEWARE.append( + "django_browser_reload.middleware.BrowserReloadMiddleware") MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware") DAISY_SETTINGS = { @@ -164,7 +203,7 @@ STATIC_ROOT = BASE_DIR / "staticfiles" STATIC_URL = "/static/" # https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS -STATICFILES_DIRS = [] +STATICFILES_DIRS = [BASE_DIR / "static"] # https://docs.djangoproject.com/en/dev/ref/settings/#media-root MEDIA_ROOT = BASE_DIR / "media" @@ -211,7 +250,9 @@ INTERNAL_IPS = [ # for docker development hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) -INTERNAL_IPS.append([ip[:-1] + "1" for ip in ips]) +for ip in ips: + INTERNAL_IPS.append(ip) + ALLOWED_HOSTS.append(ip) # https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model AUTH_USER_MODEL = "accounts.CustomUser" diff --git a/django_project/urls.py b/django_project/urls.py index 5d95763..505ad30 100644 --- a/django_project/urls.py +++ b/django_project/urls.py @@ -10,7 +10,6 @@ urlpatterns = [ path('account/', include('accounts.urls')), path("trades/", include("trades.urls")), path("__reload__/", include("django_browser_reload.urls")), - #path('silk/', include('silk.urls', namespace='silk')), ] if settings.DEBUG: diff --git a/django_project/wsgi.py b/django_project/wsgi.py index 82acc09..41fc4e0 100644 --- a/django_project/wsgi.py +++ b/django_project/wsgi.py @@ -5,3 +5,4 @@ from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings") application = get_wsgi_application() +app = application diff --git a/docker-compose_entire_app.yml b/docker-compose_entire_app.yml index ff7f0eb..4311355 100644 --- a/docker-compose_entire_app.yml +++ b/docker-compose_entire_app.yml @@ -1,7 +1,7 @@ services: web: build: . - command: python /code/manage.py runserver 0.0.0.0:8000 + #command: python /code/manage.py runserver 0.0.0.0:8000 volumes: - .:/code:z ports: diff --git a/fly.toml b/fly.toml index ba16239..65697ae 100644 --- a/fly.toml +++ b/fly.toml @@ -12,6 +12,7 @@ console_command = '/code/manage.py shell' [deploy] release_command = 'bash deploy.sh' + strategy = 'bluegreen' [env] PORT = '8000' @@ -24,9 +25,16 @@ console_command = '/code/manage.py shell' min_machines_running = 0 processes = ['app'] +[[http_service.checks]] + grace_period = "15s" + interval = "30s" + method = "GET" + timeout = "10s" + path = "/health" + [[vm]] - size = 'shared-cpu-4x' - memory = '1gb' + size = 'shared-cpu-8x' + memory = '2gb' [[statics]] guest_path = '/code/static' diff --git a/home/urls.py b/home/urls.py index 9dadbe0..0eae707 100644 --- a/home/urls.py +++ b/home/urls.py @@ -1,7 +1,9 @@ from django.urls import path -from .views import HomePageView +from .views import HomePageView, HealthCheckView urlpatterns = [ path("", HomePageView.as_view(), name="home"), + path("health", HealthCheckView.as_view(), name="health"), + path("health/", HealthCheckView.as_view(), name="health"), ] diff --git a/home/views.py b/home/views.py index 2010bdc..f931397 100644 --- a/home/views.py +++ b/home/views.py @@ -10,7 +10,8 @@ from django.utils.decorators import method_decorator from django.template.response import TemplateResponse from django.http import HttpResponseRedirect import logging -#from silk.profiling.profiler import silk_profile +from django.views import View +from django.http import HttpResponse logger = logging.getLogger(__name__) @@ -113,4 +114,8 @@ class HomePageView(TemplateView): def get(self, request, *args, **kwargs): """Override get method to add caching""" - return super().get(request, *args, **kwargs) \ No newline at end of file + return super().get(request, *args, **kwargs) + +class HealthCheckView(View): + def get(self, request, *args, **kwargs): + return HttpResponse("OK/HEALTHY") diff --git a/scripts/reset-db_make-migrations_seed-data.sh b/scripts/reset-db_make-migrations_seed-data.sh index 33db375..35ca433 100755 --- a/scripts/reset-db_make-migrations_seed-data.sh +++ b/scripts/reset-db_make-migrations_seed-data.sh @@ -14,6 +14,9 @@ docker compose -f docker-compose_db_only.yml down \ echo "Waiting for the database to be ready..." sleep 10 +echo "Resetting static files..." +uv run python manage.py collectstatic -c --no-input + echo "Running makemigrations..." uv run python manage.py makemigrations diff --git a/theme/static/css/base.css b/static/css/base.css similarity index 100% rename from theme/static/css/base.css rename to static/css/base.css diff --git a/theme/static/css/card-multiselect.css b/static/css/card-multiselect.css similarity index 100% rename from theme/static/css/card-multiselect.css rename to static/css/card-multiselect.css diff --git a/theme/static/css/choices.min.css b/static/css/choices.min.css similarity index 100% rename from theme/static/css/choices.min.css rename to static/css/choices.min.css diff --git a/theme/static/css/hovercards.min.css b/static/css/hovercards.min.css similarity index 100% rename from theme/static/css/hovercards.min.css rename to static/css/hovercards.min.css diff --git a/theme/static/images/favicon.ico b/static/images/favicon.ico similarity index 100% rename from theme/static/images/favicon.ico rename to static/images/favicon.ico diff --git a/theme/static/js/alpinejs.collapse@3.14.8.min.js b/static/js/alpinejs.collapse@3.14.8.min.js similarity index 100% rename from theme/static/js/alpinejs.collapse@3.14.8.min.js rename to static/js/alpinejs.collapse@3.14.8.min.js diff --git a/theme/static/js/alpinejs@3.14.8.min.js b/static/js/alpinejs@3.14.8.min.js similarity index 100% rename from theme/static/js/alpinejs@3.14.8.min.js rename to static/js/alpinejs@3.14.8.min.js diff --git a/theme/static/js/base.js b/static/js/base.js similarity index 100% rename from theme/static/js/base.js rename to static/js/base.js diff --git a/theme/static/js/card-multiselect.js b/static/js/card-multiselect.js similarity index 100% rename from theme/static/js/card-multiselect.js rename to static/js/card-multiselect.js diff --git a/theme/static/js/choices.min.js b/static/js/choices.min.js similarity index 100% rename from theme/static/js/choices.min.js rename to static/js/choices.min.js diff --git a/theme/static/js/floating-ui_core@1.6.9.9.min.js b/static/js/floating-ui_core@1.6.9.9.min.js similarity index 100% rename from theme/static/js/floating-ui_core@1.6.9.9.min.js rename to static/js/floating-ui_core@1.6.9.9.min.js diff --git a/theme/static/js/floating-ui_dom@1.6.13.13.min.js b/static/js/floating-ui_dom@1.6.13.13.min.js similarity index 100% rename from theme/static/js/floating-ui_dom@1.6.13.13.min.js rename to static/js/floating-ui_dom@1.6.13.13.min.js diff --git a/theme/static/js/hovercards.min.js b/static/js/hovercards.min.js similarity index 100% rename from theme/static/js/hovercards.min.js rename to static/js/hovercards.min.js diff --git a/theme/static/js/tooltip.js b/static/js/tooltip.js similarity index 100% rename from theme/static/js/tooltip.js rename to static/js/tooltip.js diff --git a/theme/templatetags/trade_acceptance.html b/theme/templatetags/trade_acceptance.html index cfe86bd..75042bc 100644 --- a/theme/templatetags/trade_acceptance.html +++ b/theme/templatetags/trade_acceptance.html @@ -25,12 +25,12 @@