Files
mnemosyne/docker/entrypoint.sh
Robert Helewka afcbee8819
All checks were successful
CVE Scan & Docker Build / security-scan (push) Successful in 51s
CVE Scan & Docker Build / build-and-push (push) Successful in 2m31s
docs(bootstrap): clarify three-step Docker first-boot flow
Rework README and docker-compose comments to document the deliberate
chicken-and-egg escape: the `init` sidecar now only runs `migrate` and
`load_library_types`, leaving `setup_neo4j_indexes` as a manual step
after the system embedding model is configured in `/admin/`. This
avoids making `app` unreachable on first boot when no embedding model
row exists yet, while preserving loud failure on dimension mismatch.
2026-05-10 16:15:28 -04:00

97 lines
3.2 KiB
Bash

#!/bin/sh
# Mnemosyne container entrypoint.
#
# The same image runs all three processes — the compose service supplies
# `web`, `mcp`, `worker`, or `migrate` as CMD.
set -e
case "$1" in
web)
# Django REST API + admin (gunicorn → wsgi).
exec gunicorn \
--config /app/docker/gunicorn.conf.py \
--bind 0.0.0.0:8000 \
--workers "${GUNICORN_WORKERS:-3}" \
--access-logfile - \
--error-logfile - \
mnemosyne.wsgi:application
;;
mcp)
# FastMCP over Streamable HTTP at /mcp/, mounted by mnemosyne.asgi.
exec uvicorn \
--host 0.0.0.0 \
--port 8001 \
--workers "${UVICORN_WORKERS:-1}" \
mnemosyne.asgi:app
;;
worker)
# Celery worker covering embedding + ingest + batch + default queues.
# In production you may want to split these onto separate worker
# services for queue-level isolation; one process is fine to start.
exec celery -A mnemosyne worker \
--loglevel="${CELERY_LOG_LEVEL:-info}" \
--queues="${CELERY_QUEUES:-celery,embedding,batch}" \
--concurrency="${CELERY_CONCURRENCY:-2}"
;;
beat)
# Celery scheduled tasks (only needed if/when periodic jobs are wired).
exec celery -A mnemosyne beat \
--loglevel="${CELERY_LOG_LEVEL:-info}"
;;
migrate)
# One-shot DB migration runner — invoke before bringing services up
# for the first time or after a deploy.
exec python manage.py migrate --noinput
;;
setup)
# One-shot init — Neo4j indexes + library_type seed data. Run this
# manually after the system embedding model has been configured in the
# admin (setup_neo4j_indexes reads vector dimensions from that row).
python manage.py setup_neo4j_indexes
python manage.py load_library_types
;;
init)
# Bundled one-shot init run by the `init` sidecar on every
# `docker compose up`. Idempotent: re-runs are no-ops unless migrations
# or library_type defaults need to change. A non-zero exit here blocks
# `app`, `mcp`, and `worker` from starting.
#
# Neo4j vector-index creation is *deliberately not* bundled here. That
# command (``setup_neo4j_indexes``) requires a system embedding model
# with a configured ``vector_dimensions`` value, and that model is
# data an operator configures through the Django admin after first
# boot. On a fresh stack there is no such row yet, so blocking the
# whole stack on it would make the admin unreachable — a chicken-and-
# egg. Operator bootstrap flow:
#
# 1. docker compose up # init sidecar: migrate + load_library_types
# 2. browse to admin, configure system embedding model
# 3. docker compose exec app python manage.py setup_neo4j_indexes
#
# Until step 3 runs, vector search will return empty results — the
# readiness check in library/apps.py logs a warning when indexes are
# missing so this is visible, not silent.
set -e
python manage.py migrate --noinput
python manage.py load_library_types
;;
shell)
# Drop into the management shell for ad-hoc work.
exec python manage.py shell
;;
*)
# Fall through: run whatever was passed (e.g. `manage.py <cmd>`).
exec "$@"
;;
esac