Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ RUN python3 manage.py collectstatic --noinput --verbosity 2
# Expose ports
EXPOSE 80 8000

HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=5 \
CMD ["python3", "/code/healthcheck.py"]

# Start with an entrypoint that runs init tasks then starts supervisord
ENTRYPOINT ["/code/entrypoint.sh"]

Expand Down
30 changes: 30 additions & 0 deletions backend/server/healthcheck.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
import os
import sys
import urllib.error
import urllib.request


def main() -> int:
timeout = float(os.getenv('HEALTHCHECK_TIMEOUT_SECONDS', '3'))
urls = os.getenv(
'HEALTHCHECK_URLS',
'http://127.0.0.1:8000/healthz,http://127.0.0.1/healthz',
)

for raw_url in urls.split(','):
url = raw_url.strip()
if not url:
continue
try:
with urllib.request.urlopen(url, timeout=timeout) as response:
if response.status == 200:
return 0
except (OSError, urllib.error.URLError):
continue

return 1


if __name__ == '__main__':
sys.exit(main())
5 changes: 3 additions & 2 deletions backend/server/main/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.contrib import admin
from django.views.generic import RedirectView, TemplateView
from users.views import IsRegistrationDisabled, PublicUserListView, PublicUserDetailView, UserMetadataView, UpdateUserMetadataView, EnabledSocialProvidersView, DisablePasswordAuthenticationView
from .views import get_csrf_token, get_public_url, serve_protected_media
from .views import get_csrf_token, get_public_url, healthz, serve_protected_media
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

Expand All @@ -13,6 +13,7 @@
)
)
urlpatterns = [
path('healthz/', healthz, name='healthz'),
path('api/', include('adventures.urls')),
path('api/', include('worldtravel.urls')),
path("auth/", include("allauth.headless.urls")),
Expand Down Expand Up @@ -49,4 +50,4 @@
path("api/integrations/", include("integrations.urls")),

# Include the API endpoints:
]
]
7 changes: 6 additions & 1 deletion backend/server/main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
from django.views.static import serve
from adventures.utils.file_permissions import checkFilePermission


def healthz(request):
return HttpResponse('ok', content_type='text/plain')


def get_csrf_token(request):
csrf_token = get_token(request)
return JsonResponse({'csrfToken': csrf_token})
Expand Down Expand Up @@ -39,4 +44,4 @@ def serve_protected_media(request, path):
response = HttpResponse()
response['Content-Type'] = ''
response['X-Accel-Redirect'] = '/protectedMedia/' + path
return response
return response
15 changes: 14 additions & 1 deletion docker-compose-traefik.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ services:
- "traefik.http.routers.adventurelogweb.tls=true"
- "traefik.http.routers.adventurelogweb.tls.certresolver=letsencrypt"
depends_on:
- server
server:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "/app/healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s

server:
image: ghcr.io/seanmorley15/adventurelog-backend:latest
Expand Down Expand Up @@ -71,6 +78,12 @@ services:
- "traefik.http.routers.adventurelogserver.tls.certresolver=letsencrypt"
depends_on:
- db
healthcheck:
test: ["CMD", "python3", "/code/healthcheck.py"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s

volumes:
postgres-data:
Expand Down
15 changes: 14 additions & 1 deletion docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@ services:
ports:
- "${FRONTEND_PORT:-8015}:3000"
depends_on:
- server
server:
condition: service_healthy
volumes:
- ./frontend:/app
- pnpm_store:/pnpm-store
command: sh -c "mkdir -p /pnpm-store && chown -R node:node /pnpm-store && su node -c 'pnpm config set store-dir /pnpm-store && pnpm install --frozen-lockfile && pnpm exec vite dev --host 0.0.0.0 --port 3000 --strictPort'"
healthcheck:
test: ["CMD", "node", "/app/healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s

db:
image: postgis/postgis:16-3.5
Expand Down Expand Up @@ -52,6 +59,12 @@ services:
python manage.py createsuperuser --noinput --username \"$$DJANGO_SUPERUSER_USERNAME\" --email \"$$DJANGO_SUPERUSER_EMAIL\" || true;
fi;
python manage.py runserver 0.0.0.0:8000"
healthcheck:
test: ["CMD", "python3", "/code/healthcheck.py"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s

volumes:
postgres_data:
Expand Down
15 changes: 14 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ services:
ports:
- "${FRONTEND_PORT:-8015}:3000"
depends_on:
- server
server:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "/app/healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s

db:
image: postgis/postgis:16-3.5
Expand All @@ -30,6 +37,12 @@ services:
- db
volumes:
- adventurelog_media:/code/media/
healthcheck:
test: ["CMD", "python3", "/code/healthcheck.py"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s

volumes:
postgres_data:
Expand Down
5 changes: 4 additions & 1 deletion frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@ USER node:node
# Expose the port that the app is listening on
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=5 \
CMD ["node", "/app/healthcheck.mjs"]

# Run startup.sh instead of the default command
CMD ["./startup.sh"]
CMD ["./startup.sh"]
27 changes: 27 additions & 0 deletions frontend/healthcheck.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const timeoutMs = Number.parseInt(process.env.HEALTHCHECK_TIMEOUT_MS ?? '3000', 10);
const urls = (process.env.HEALTHCHECK_URLS ?? 'http://127.0.0.1:3000/healthz')
.split(',')
.map((url) => url.trim())
.filter(Boolean);

for (const url of urls) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);

try {
const response = await fetch(url, {
method: 'GET',
signal: controller.signal,
cache: 'no-store'
});
if (response.status === 200) {
process.exit(0);
}
} catch (_) {
// Continue to the next URL.
} finally {
clearTimeout(timer);
}
}

process.exit(1);
10 changes: 10 additions & 0 deletions frontend/src/routes/healthz/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async () => {
return new Response('ok', {
status: 200,
headers: {
'Content-Type': 'text/plain'
}
});
};
Loading