diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 54c3bd2..eea5bd5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,6 +51,37 @@ jobs: EPHEMERIS_DIR: ${{ github.workspace }}/services/logic/.ephemeris run: pytest tests -q -rs + swisseph-image: + name: Build obrazu silnika B (swisseph) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Obraz kompiluje pyswisseph ze źródeł (brak wheeli dla cp312), więc ten + # build jest realnym testem Dockerfile'a — nie tylko pobraniem paczek. + - name: docker build + run: docker build -t astrololo/engine-swisseph:ci services/engine-swisseph + + - name: Smoke test (health + pozycje) + run: | + docker run -d --name swe -p 8003:8003 astrololo/engine-swisseph:ci + for i in $(seq 1 30); do + curl -fsS http://localhost:8003/health >/dev/null 2>&1 && break + sleep 1 + done + curl -fsS http://localhost:8003/health + echo + # Horoskop referencyjny (30.04.1984) — ten sam, na którym opieramy testy + # silnika własnego; sprawdzamy, że silnik B faktycznie liczy. + curl -fsS -X POST http://localhost:8003/positions \ + -H 'Content-Type: application/json' \ + -d '{"when_utc":"1984-04-30T09:20:00Z","lat":50.0647,"lon":19.9450}' + echo + + - name: Logi kontenera (gdy coś padło) + if: failure() + run: docker logs swe || true + compile-all: name: Kontrola składni wszystkich warstw runs-on: ubuntu-latest diff --git a/services/engine-swisseph/Dockerfile b/services/engine-swisseph/Dockerfile index cb2f4dc..59a03b8 100644 --- a/services/engine-swisseph/Dockerfile +++ b/services/engine-swisseph/Dockerfile @@ -1,10 +1,34 @@ +# Build wieloetapowy — bo `pyswisseph` to rozszerzenie C bez gotowych wheeli. +# +# Na PyPI (2.10.3.2) wheels kończą się na cp311 i obejmują wyłącznie i686/x86_64. +# Dla Pythona 3.12 oraz dla arm64 pip ZAWSZE kompiluje ze źródeł, a `-slim` nie ma +# kompilatora — dlatego jednoetapowy build tu padał. Kompilujemy w etapie builder, +# a do obrazu finalnego wchodzi już tylko gotowy wheel (bez toolchaina). + +FROM python:3.12-slim AS builder + +RUN apt-get update \ + && apt-get install -y --no-install-recommends build-essential \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build +COPY requirements.txt . +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt + + FROM python:3.12-slim WORKDIR /app +COPY --from=builder /wheels /wheels COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir --no-index --find-links=/wheels -r requirements.txt \ + && rm -rf /wheels COPY . . +# Sanity check na etapie budowania: brak działającego swissepha ma wywalić build, +# a nie dopiero pierwszy request. +RUN python -c "import swisseph as swe; swe.set_ephe_path(None); print('swisseph OK', swe.version)" + EXPOSE 8003 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8003"] diff --git a/services/engine-swisseph/README.md b/services/engine-swisseph/README.md index 5101d80..23806f9 100644 --- a/services/engine-swisseph/README.md +++ b/services/engine-swisseph/README.md @@ -15,9 +15,23 @@ permisywnej reszty systemu. **Nie wchodzi do dystrybucji zamkniętego produktu.* Tryb Moshiera (`FLG_MOSEPH`) — bez plików efemeryd, zero konfiguracji. +## Build obrazu +```bash +docker compose --profile comparison build engine-swisseph +``` +Dockerfile jest **wieloetapowy** i to nie jest ozdobnik: `pyswisseph` to rozszerzenie +C, a na PyPI (2.10.3.2) gotowe wheels kończą się na **cp311** i obejmują wyłącznie +**i686/x86_64**. Dla Pythona 3.12 oraz dla arm64 pip musi kompilować ze źródeł, więc +sam `python:3.12-slim` (bez kompilatora) build wywracał. Kompilacja idzie w etapie +`builder` (`build-essential`), a do obrazu finalnego trafia już tylko gotowy wheel — +runtime zostaje czysty i mały. Pierwszy build trwa ~1–2 min, kolejne idą z cache warstw. + +Build kończy się sanity-checkiem (`import swisseph`), żeby niedziałający silnik +wykrzaczył build, a nie dopiero pierwszy request. + ## Uruchomienie (tylko profil porównawczy / dev / CI) ```bash -pip install -r requirements.txt +pip install -r requirements.txt # wymaga kompilatora C (patrz wyżej) uvicorn app.main:app --port 8003 ``` Następnie w warstwie logicznej ustaw `ENGINE_SWISSEPH_URL=http://localhost:8003`,