x-app-env: &app-env # NB: hardcoded to Postgres — .env may contain sqlite for local CLI, don't let it leak here IAAI_DATABASE_URL: postgresql+psycopg2://iaai:iaai@postgres:5432/iaai_scraper IAAI_REDIS_URL: ${IAAI_REDIS_URL:-redis://redis:6379/0} CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis:6379/0} CELERY_RESULT_BACKEND: ${CELERY_RESULT_BACKEND:-redis://redis:6379/0} IAAI_DATABASE_POOL_RECYCLE_SECONDS: ${IAAI_DATABASE_POOL_RECYCLE_SECONDS:-1800} CELERY_TASK_SOFT_TIME_LIMIT: ${CELERY_TASK_SOFT_TIME_LIMIT:-3300} CELERY_TASK_TIME_LIMIT: ${CELERY_TASK_TIME_LIMIT:-3600} CELERY_BROKER_VISIBILITY_TIMEOUT: ${CELERY_BROKER_VISIBILITY_TIMEOUT:-7200} # 0 => без лимита (в коде интерпретируется как None). # После первичного полного прохода hourly-режим должен успевать за всеми новыми авто. CELERY_BEAT_SYNC_LIMIT: ${CELERY_BEAT_SYNC_LIMIT:-0} CELERY_WORKER_MAX_TASKS_PER_CHILD: ${CELERY_WORKER_MAX_TASKS_PER_CHILD:-5} CELERY_BATCH_SIZE: ${CELERY_BATCH_SIZE:-200} IAAI_PARALLEL_TABS: ${IAAI_PARALLEL_TABS:-40} IAAI_BLOCK_RESOURCES: ${IAAI_BLOCK_RESOURCES:-true} IAAI_LISTING_SEGMENTS: ${IAAI_LISTING_SEGMENTS:-auto} IAAI_MAX_PAGES_PER_RUN: ${IAAI_MAX_PAGES_PER_RUN:-9999} IAAI_MAX_VEHICLES_PER_RUN: ${IAAI_MAX_VEHICLES_PER_RUN:-50000} IAAI_HUMAN_PACE_ENABLED: ${IAAI_HUMAN_PACE_ENABLED:-true} IAAI_TOKENS_FILE: ${IAAI_TOKENS_FILE:-/data/tokens.json} IAAI_RUNTIME_CONFIG_FILE: ${IAAI_RUNTIME_CONFIG_FILE:-/app/runtime_config.json} IAAI_BROWSER_ENGINE: chromium TZ: ${TZ:-UTC} x-env-file: &env-file - path: .env required: false x-app-service: &app-service build: . env_file: *env-file environment: *app-env volumes: - ./runtime_config.json:/app/runtime_config.json:ro x-worker-service: &worker-service <<: *app-service volumes: - ./runtime_config.json:/app/runtime_config.json:ro - tokens_data:/data services: # PostgreSQL postgres: image: postgres:16-alpine container_name: iaai-postgres restart: unless-stopped environment: POSTGRES_USER: iaai POSTGRES_PASSWORD: iaai POSTGRES_DB: iaai_scraper ports: - "127.0.0.1:5432:5432" volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U iaai -d iaai_scraper"] interval: 5s timeout: 3s retries: 5 logging: driver: json-file options: max-size: "10m" max-file: "5" # Redis (Celery broker) redis: image: redis:7-alpine container_name: iaai-redis restart: unless-stopped ports: - "127.0.0.1:6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 command: > redis-server --appendonly yes --save 60 1000 volumes: - redisdata:/data logging: driver: json-file options: max-size: "10m" max-file: "5" # DB migrations migrate: <<: *app-service container_name: iaai-migrate restart: "no" depends_on: postgres: condition: service_healthy command: alembic upgrade head # FastAPI api: <<: *app-service container_name: iaai-api restart: unless-stopped ports: - "127.0.0.1:8000:8000" depends_on: migrate: condition: service_completed_successfully redis: condition: service_healthy command: > uvicorn iaai_scraper.api.app:app --host 0.0.0.0 --port 8000 --workers 1 healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5)"] interval: 30s timeout: 10s retries: 3 start_period: 40s stop_grace_period: 30s logging: driver: json-file options: max-size: "10m" max-file: "5" # Celery Worker worker: <<: *worker-service container_name: iaai-worker restart: unless-stopped init: true depends_on: migrate: condition: service_completed_successfully redis: condition: service_healthy stop_grace_period: 60s command: > celery -A iaai_scraper.worker.celery_app worker --loglevel=info --concurrency=${CELERY_WORKER_CONCURRENCY:-4} --pool=prefork --pidfile=/tmp/celery-worker.pid -Q scraping --max-tasks-per-child=${CELERY_WORKER_MAX_TASKS_PER_CHILD:-5} healthcheck: test: ["CMD-SHELL", "test -f /tmp/celery-worker.pid && kill -0 $(cat /tmp/celery-worker.pid)"] interval: 60s timeout: 10s retries: 3 start_period: 90s logging: driver: json-file options: max-size: "10m" max-file: "5" # Celery Beat (периодический планировщик) beat: <<: *worker-service container_name: iaai-beat restart: unless-stopped init: true depends_on: migrate: condition: service_completed_successfully redis: condition: service_healthy command: > celery -A iaai_scraper.worker.celery_app beat --loglevel=info --pidfile=/tmp/celery-beat.pid --schedule=/tmp/celerybeat-schedule healthcheck: test: ["CMD-SHELL", "test -f /tmp/celery-beat.pid && kill -0 $(cat /tmp/celery-beat.pid)"] interval: 60s timeout: 10s retries: 3 start_period: 90s logging: driver: json-file options: max-size: "10m" max-file: "5" volumes: pgdata: redisdata: tokens_data: