- NSPD-skraper переехал в backend/app/services/scrapers/nspd_kn.py + Celery task scrape_nspd_region (beat: 20-е февраля/мая/авг/нояб). Redis lock 3h, WAF auto-retry, heartbeat в nspd_scrape_runs. - Recommend_mix Tier 3: per-bucket elasticity через регрессию по «доминирующему bucket» каждого ЖК. Weighted-elasticity для inverse-mode. UI показывает разброс эластичностей и переключение regression/fallback. - Cadastre vs market cross-check: spatial-join cad_buildings → ekb_districts_geom; cadastre_vs_market_pct в scope, аномалии (>+50% / <-30%) подсвечены в UI. - Sentry release tracking (#4): IMAGE_TAG → backend/.env.runtime → sentry_sdk.init(release=...). Compose v2 env_file optional path. Schemas: 63_schema_nspd_runs.sql (cad_buildings + nspd_scrape_runs/log формализуют то, что уже жило в проде через 61_import_nspd_batch.py), 64_v_zk_rosreestr_velocity.sql (refresh с cad_buildings).
117 lines
4.1 KiB
YAML
117 lines
4.1 KiB
YAML
name: Deploy
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
workflow_dispatch:
|
||
|
||
concurrency:
|
||
group: deploy-prod
|
||
cancel-in-progress: false
|
||
|
||
env:
|
||
IMAGE_BACKEND: ghcr.io/lekss361/gendesign-backend
|
||
IMAGE_WORKER: ghcr.io/lekss361/gendesign-worker
|
||
IMAGE_FRONTEND: ghcr.io/lekss361/gendesign-frontend
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set image tag
|
||
id: meta
|
||
run: echo "tag=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Login to GHCR
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.actor }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Build & push backend (lean — без Chromium)
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./backend
|
||
target: runner
|
||
push: true
|
||
cache-from: type=gha,scope=backend
|
||
cache-to: type=gha,mode=max,scope=backend
|
||
tags: |
|
||
${{ env.IMAGE_BACKEND }}:latest
|
||
${{ env.IMAGE_BACKEND }}:${{ steps.meta.outputs.tag }}
|
||
|
||
- name: Build & push worker (с Chromium для Playwright)
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./backend
|
||
target: runner-with-chromium
|
||
push: true
|
||
cache-from: type=gha,scope=worker
|
||
cache-to: type=gha,mode=max,scope=worker
|
||
tags: |
|
||
${{ env.IMAGE_WORKER }}:latest
|
||
${{ env.IMAGE_WORKER }}:${{ steps.meta.outputs.tag }}
|
||
|
||
- name: Build & push frontend
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: ./frontend
|
||
push: true
|
||
cache-from: type=gha,scope=frontend
|
||
cache-to: type=gha,mode=max,scope=frontend
|
||
tags: |
|
||
${{ env.IMAGE_FRONTEND }}:latest
|
||
${{ env.IMAGE_FRONTEND }}:${{ steps.meta.outputs.tag }}
|
||
|
||
- name: Deploy to VM via SSH
|
||
uses: appleboy/ssh-action@v1.0.3
|
||
env:
|
||
IMAGE_TAG: ${{ steps.meta.outputs.tag }}
|
||
with:
|
||
host: ${{ secrets.DEPLOY_HOST }}
|
||
username: ${{ secrets.DEPLOY_USER }}
|
||
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||
envs: IMAGE_TAG
|
||
script: |
|
||
set -euo pipefail
|
||
cd /opt/gendesign
|
||
|
||
# Sync compose / Caddyfile / init scripts from the repo.
|
||
# --ff-only refuses if there are local commits on the VM (we don't expect any).
|
||
git fetch origin main
|
||
git reset --hard origin/main
|
||
|
||
# Sentry release tracking — записываем git-sha в .env.runtime
|
||
# (отдельный файл, чтобы не трогать ручной .env с секретами).
|
||
# backend/worker/beat подхватывают его через env_file (см. compose).
|
||
mkdir -p backend
|
||
printf 'SENTRY_RELEASE=%s\n' "$IMAGE_TAG" > backend/.env.runtime
|
||
|
||
export IMAGE_TAG="$IMAGE_TAG"
|
||
docker compose -f docker-compose.prod.yml pull
|
||
docker compose -f docker-compose.prod.yml up -d
|
||
|
||
# Caddyfile is bind-mounted; up -d won't re-read it. Reload explicitly.
|
||
# `|| true` so a temporary Caddy hiccup doesn't fail the whole deploy.
|
||
docker compose -f docker-compose.prod.yml exec -T caddy \
|
||
caddy reload --config /etc/caddy/Caddyfile || true
|
||
|
||
# Clean up disk: dangling layers + tagged images older than 72h that
|
||
# nothing is using anymore. Plus build cache (we never build on prod
|
||
# but old buildkit caches may linger from earlier compose builds).
|
||
docker image prune -af --filter "until=72h" || true
|
||
docker builder prune -af || true
|
||
|
||
sleep 8
|
||
curl -fsS http://localhost:8000/health | head -c 200 || true
|