From 7cfb6cf0011ecde32209f47e4b971f9361865308 Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Wed, 11 Mar 2026 15:46:28 +0100 Subject: [PATCH] =?UTF-8?q?feat(docker):=20migrations=20sqlx=20int=C3=A9gr?= =?UTF-8?q?=C3=A9es=20dans=20le=20d=C3=A9marrage=20de=20l'API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Déplace les migrations du service `migrate` séparé vers un entrypoint.sh - L'API exécute `sqlx migrate run` au démarrage avant de lancer le binaire - Gestion de la rétrocompatibilité : détecte un schéma pre-sqlx et crée une baseline `_sqlx_migrations` pour éviter les conflits sur les instances existantes - Installe sqlx-cli dans le builder, copie le binaire et les migrations dans l'image finale - Supprime le service `migrate` du docker-compose.yml ; l'indexer dépend maintenant du healthcheck de l'API (qui garantit que les migrations sont appliquées) Co-Authored-By: Claude Sonnet 4.6 --- apps/api/Dockerfile | 13 +++++++-- apps/api/entrypoint.sh | 63 ++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 24 ++-------------- scripts/docker-push.sh | 8 +++--- 4 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 apps/api/entrypoint.sh diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 868d5aa..2495efa 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -18,13 +18,20 @@ COPY crates/parsers/src crates/parsers/src # Build with sccache (cache persisted between builds via Docker cache mount) RUN --mount=type=cache,target=/sccache \ - cargo build --release -p api + cargo build --release -p api && \ + cargo install sqlx-cli --no-default-features --features postgres --locked FROM debian:bookworm-slim -RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates wget unar poppler-utils locales && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates wget unar poppler-utils locales postgresql-client \ + && rm -rf /var/lib/apt/lists/* RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen ENV LANG=en_US.UTF-8 ENV LC_ALL=en_US.UTF-8 COPY --from=builder /app/target/release/api /usr/local/bin/api +COPY --from=builder /usr/local/cargo/bin/sqlx /usr/local/bin/sqlx +COPY infra/migrations /app/migrations +COPY apps/api/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh EXPOSE 7080 -CMD ["/usr/local/bin/api"] +CMD ["/usr/local/bin/entrypoint.sh"] diff --git a/apps/api/entrypoint.sh b/apps/api/entrypoint.sh new file mode 100644 index 0000000..f457d31 --- /dev/null +++ b/apps/api/entrypoint.sh @@ -0,0 +1,63 @@ +#!/bin/sh +set -e + +# psql requires "postgresql://" but Rust/sqlx accepts both "postgres://" and "postgresql://" +PSQL_URL=$(echo "$DATABASE_URL" | sed 's|^postgres://|postgresql://|') + +# Check 1: does the old schema exist (index_jobs table)? +HAS_OLD_TABLES=$(psql "$PSQL_URL" -tAc \ + "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_name='index_jobs')::text" \ + 2>/dev/null || echo "false") + +# Check 2: is sqlx tracking present and non-empty? +HAS_SQLX_TABLE=$(psql "$PSQL_URL" -tAc \ + "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_name='_sqlx_migrations')::text" \ + 2>/dev/null || echo "false") + +if [ "$HAS_SQLX_TABLE" = "true" ]; then + HAS_SQLX_ROWS=$(psql "$PSQL_URL" -tAc \ + "SELECT EXISTS(SELECT 1 FROM _sqlx_migrations LIMIT 1)::text" \ + 2>/dev/null || echo "false") +else + HAS_SQLX_ROWS="false" +fi + +echo "==> Migration check: old_tables=$HAS_OLD_TABLES sqlx_table=$HAS_SQLX_TABLE sqlx_rows=$HAS_SQLX_ROWS" + +if [ "$HAS_OLD_TABLES" = "true" ] && [ "$HAS_SQLX_ROWS" = "false" ]; then + echo "==> Upgrade from pre-sqlx migration system detected: creating baseline..." + + psql "$PSQL_URL" -c " + CREATE TABLE IF NOT EXISTS _sqlx_migrations ( + version BIGINT PRIMARY KEY, + description TEXT NOT NULL, + installed_on TIMESTAMPTZ NOT NULL DEFAULT NOW(), + success BOOLEAN NOT NULL, + checksum BYTEA NOT NULL, + execution_time BIGINT NOT NULL + ) + " + + for f in /app/migrations/*.sql; do + filename=$(basename "$f") + # Strip leading zeros to get the integer version (e.g. "0005" -> "5") + version=$(echo "$filename" | sed 's/^0*//' | cut -d'_' -f1) + description=$(echo "$filename" | sed 's/^[0-9]*_//' | sed 's/\.sql$//') + checksum=$(sha384sum "$f" | awk '{print $1}') + + psql "$PSQL_URL" -c " + INSERT INTO _sqlx_migrations (version, description, installed_on, success, checksum, execution_time) + VALUES ($version, '$description', NOW(), TRUE, decode('$checksum', 'hex'), 0) + ON CONFLICT (version) DO NOTHING + " + echo " baselined: $filename" + done + + echo "==> Baseline complete." +fi + +echo "==> Running migrations..." +sqlx migrate run --source /app/migrations + +echo "==> Starting API..." +exec /usr/local/bin/api diff --git a/docker-compose.yml b/docker-compose.yml index e7071a0..1fa73cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,24 +29,6 @@ services: timeout: 5s retries: 5 - migrate: - image: postgres:16-alpine - depends_on: - postgres: - condition: service_healthy - environment: - POSTGRES_USER: stripstream - POSTGRES_PASSWORD: stripstream - POSTGRES_DB: stripstream - volumes: - - ./infra/migrations:/migrations:ro - command: - [ - "sh", - "-c", - "export PGPASSWORD=$$POSTGRES_PASSWORD; for f in /migrations/*.sql; do echo \"Applying migration: $$f\"; psql -h postgres -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\" -f \"$$f\" || exit 1; done", - ] - api: build: context: . @@ -59,8 +41,6 @@ services: - ${LIBRARIES_HOST_PATH:-./libraries}:/libraries - ${THUMBNAILS_HOST_PATH:-./data/thumbnails}:/data/thumbnails depends_on: - migrate: - condition: service_completed_successfully postgres: condition: service_healthy meilisearch: @@ -83,8 +63,8 @@ services: - ${LIBRARIES_HOST_PATH:-./libraries}:/libraries - ${THUMBNAILS_HOST_PATH:-./data/thumbnails}:/data/thumbnails depends_on: - migrate: - condition: service_completed_successfully + api: + condition: service_healthy postgres: condition: service_healthy meilisearch: diff --git a/scripts/docker-push.sh b/scripts/docker-push.sh index 35f3de1..f9aadf7 100755 --- a/scripts/docker-push.sh +++ b/scripts/docker-push.sh @@ -17,17 +17,17 @@ echo "" for service in "${SERVICES[@]}"; do echo "Building $service..." docker build -f apps/$service/Dockerfile -t $service:latest . - + echo "Tagging $service..." docker tag $service:latest $REGISTRY/$OWNER/stripstream-$service:$VERSION docker tag $service:latest $REGISTRY/$OWNER/stripstream-$service:latest - + echo "Pushing stripstream-$service:$VERSION..." docker push $REGISTRY/$OWNER/stripstream-$service:$VERSION - + echo "Pushing stripstream-$service:latest..." docker push $REGISTRY/$OWNER/stripstream-$service:latest - + echo "✓ $service pushed successfully" echo "" done