build fixes and static files fix, closes #28

This commit is contained in:
badblocks 2025-04-19 17:10:46 -07:00
parent bff2525c65
commit 6a44ef30a3
26 changed files with 91 additions and 39 deletions

View file

@ -1,14 +1,12 @@
# Pull base image
FROM python:3.12.2-bookworm 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 PYTHONUNBUFFERED 1
ENV HOME /code
# Create and set work directory called `app`
RUN mkdir -p /code RUN mkdir -p /code
WORKDIR /code WORKDIR /code
# Install dependencies
COPY requirements.txt /tmp/requirements.txt COPY requirements.txt /tmp/requirements.txt
RUN set -ex && \ RUN set -ex && \
@ -16,20 +14,16 @@ RUN set -ex && \
pip install -r /tmp/requirements.txt && \ pip install -r /tmp/requirements.txt && \
rm -rf /root/.cache/ 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 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 RUN playwright install-deps && playwright install
# Expose port 8000 COPY . /code/
COPY .env.production /code/.env
EXPOSE 8000 EXPOSE 8000
HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1 HEALTHCHECK CMD curl --fail http://localhost:8000 || exit 1
# Use gunicorn on port 8000 #CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--workers", "3", "--worker-class", "gevent", "--worker-connections", "1000", "--worker-tmp-dir", "/dev/shm", "--timeout", "90"]
CMD ["gunicorn", "--bind", ":8000", "django_project.wsgi", "--workers", "4", "--worker-tmp-dir", "/dev/shm", "--timeout", "90"] CMD ["granian", "--interface", "wsgi", "django_project.wsgi", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
python manage.py migrate --noinput python manage.py migrate --noinput
python manage.py clear_cache python manage.py clear_cache
python manage.py collectstatic --noinput python manage.py collectstatic -c --no-input

View file

@ -1,19 +1,18 @@
from django.conf import settings from django.conf import settings
from django.contrib.auth import login from django.contrib.auth import login
from accounts.models import CustomUser import time
from django.contrib.auth.models import User import logging
class AutoLoginMiddleware: class LogRequestsMiddleware:
"""
In development, automatically logs in as a predefined user if the request is anonymous.
"""
def __init__(self, get_response): def __init__(self, get_response):
self.get_response = get_response self.get_response = get_response
def __call__(self, request): def __call__(self, request):
# Only perform auto-login if in DEBUG mode and user is not authenticated. start = time.perf_counter()
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')
response = self.get_response(request) response = self.get_response(request)
return response 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")

View file

@ -2,11 +2,48 @@ import socket
from pathlib import Path from pathlib import Path
import environ import environ
import os import os
import logging
import sys
env = environ.Env( env = environ.Env(
DEBUG=(bool, False) 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'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -80,10 +117,12 @@ MIDDLEWARE = [
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware",
"allauth.account.middleware.AccountMiddleware", # django-allauth "allauth.account.middleware.AccountMiddleware", # django-allauth
"django_project.middleware.LogRequestsMiddleware",
] ]
if DEBUG: if DEBUG:
MIDDLEWARE.append("django_browser_reload.middleware.BrowserReloadMiddleware") MIDDLEWARE.append(
"django_browser_reload.middleware.BrowserReloadMiddleware")
MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware") MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware")
DAISY_SETTINGS = { DAISY_SETTINGS = {
@ -164,7 +203,7 @@ STATIC_ROOT = BASE_DIR / "staticfiles"
STATIC_URL = "/static/" STATIC_URL = "/static/"
# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS # 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 # https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = BASE_DIR / "media" MEDIA_ROOT = BASE_DIR / "media"
@ -211,7 +250,9 @@ INTERNAL_IPS = [
# for docker development # for docker development
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) 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 # https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model
AUTH_USER_MODEL = "accounts.CustomUser" AUTH_USER_MODEL = "accounts.CustomUser"

View file

@ -10,7 +10,6 @@ urlpatterns = [
path('account/', include('accounts.urls')), path('account/', include('accounts.urls')),
path("trades/", include("trades.urls")), path("trades/", include("trades.urls")),
path("__reload__/", include("django_browser_reload.urls")), path("__reload__/", include("django_browser_reload.urls")),
#path('silk/', include('silk.urls', namespace='silk')),
] ]
if settings.DEBUG: if settings.DEBUG:

View file

@ -5,3 +5,4 @@ from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings")
application = get_wsgi_application() application = get_wsgi_application()
app = application

View file

@ -1,7 +1,7 @@
services: services:
web: web:
build: . build: .
command: python /code/manage.py runserver 0.0.0.0:8000 #command: python /code/manage.py runserver 0.0.0.0:8000
volumes: volumes:
- .:/code:z - .:/code:z
ports: ports:

View file

@ -12,6 +12,7 @@ console_command = '/code/manage.py shell'
[deploy] [deploy]
release_command = 'bash deploy.sh' release_command = 'bash deploy.sh'
strategy = 'bluegreen'
[env] [env]
PORT = '8000' PORT = '8000'
@ -24,9 +25,16 @@ console_command = '/code/manage.py shell'
min_machines_running = 0 min_machines_running = 0
processes = ['app'] processes = ['app']
[[http_service.checks]]
grace_period = "15s"
interval = "30s"
method = "GET"
timeout = "10s"
path = "/health"
[[vm]] [[vm]]
size = 'shared-cpu-4x' size = 'shared-cpu-8x'
memory = '1gb' memory = '2gb'
[[statics]] [[statics]]
guest_path = '/code/static' guest_path = '/code/static'

View file

@ -1,7 +1,9 @@
from django.urls import path from django.urls import path
from .views import HomePageView from .views import HomePageView, HealthCheckView
urlpatterns = [ urlpatterns = [
path("", HomePageView.as_view(), name="home"), path("", HomePageView.as_view(), name="home"),
path("health", HealthCheckView.as_view(), name="health"),
path("health/", HealthCheckView.as_view(), name="health"),
] ]

View file

@ -10,7 +10,8 @@ from django.utils.decorators import method_decorator
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
import logging import logging
#from silk.profiling.profiler import silk_profile from django.views import View
from django.http import HttpResponse
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -113,4 +114,8 @@ class HomePageView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
"""Override get method to add caching""" """Override get method to add caching"""
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
class HealthCheckView(View):
def get(self, request, *args, **kwargs):
return HttpResponse("OK/HEALTHY")

View file

@ -14,6 +14,9 @@ docker compose -f docker-compose_db_only.yml down \
echo "Waiting for the database to be ready..." echo "Waiting for the database to be ready..."
sleep 10 sleep 10
echo "Resetting static files..."
uv run python manage.py collectstatic -c --no-input
echo "Running makemigrations..." echo "Running makemigrations..."
uv run python manage.py makemigrations uv run python manage.py makemigrations

View file

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 549 B

Before After
Before After

View file

@ -25,12 +25,12 @@
</a> </a>
<!-- Main Card Row: Single row with the acceptance's cards --> <!-- Main Card Row: Single row with the acceptance's cards -->
<div class="px-2 pb-0"> <div class="px-2 pb-0">
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center gap-2">
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<div class="cursor-pointer">{% card_badge acceptance.requested_card %}</div> {% card_badge acceptance.requested_card %}
</div> </div>
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<div class="cursor-pointer">{% card_badge acceptance.offered_card %}</div> {% card_badge acceptance.offered_card %}
</div> </div>
</div> </div>
</div> </div>