x-app-env: &app-env # Database (отдельная БД для Encar, порт 5433) ENCAR_DATABASE_URL: postgresql+psycopg2://encar:encar@postgres:5432/encar_db ENCAR_DATABASE_POOL_RECYCLE_SECONDS: ${ENCAR_DATABASE_POOL_RECYCLE_SECONDS:-1800} # Redis / Celery (порт 6380, db=1) ENCAR_REDIS_URL: ${ENCAR_REDIS_URL:-redis://redis:6379/1} CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis:6379/1} CELERY_RESULT_BACKEND: ${CELERY_RESULT_BACKEND:-redis://redis:6379/1} CELERY_TASK_SOFT_TIME_LIMIT: ${CELERY_TASK_SOFT_TIME_LIMIT:-14400} CELERY_TASK_TIME_LIMIT: ${CELERY_TASK_TIME_LIMIT:-14520} CELERY_BROKER_VISIBILITY_TIMEOUT: ${CELERY_BROKER_VISIBILITY_TIMEOUT:-15000} CELERY_WORKER_MAX_TASKS_PER_CHILD: ${CELERY_WORKER_MAX_TASKS_PER_CHILD:-50} # Encar settings ENCAR_BEAT_INTERVAL_MINUTES: ${ENCAR_BEAT_INTERVAL_MINUTES:-60} ENCAR_BEAT_LIMIT: ${ENCAR_BEAT_LIMIT:-0} 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 services: # PostgreSQL (порт 5434 наружу) postgres: image: postgres:16-alpine container_name: encar-postgres restart: unless-stopped environment: POSTGRES_USER: encar POSTGRES_PASSWORD: encar POSTGRES_DB: encar_db ports: - "127.0.0.1:5434:5432" volumes: - encar_pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U encar -d encar_db"] interval: 5s timeout: 3s retries: 5 logging: driver: json-file options: max-size: "10m" max-file: "5" # Redis (порт 6380 наружу) redis: image: redis:7-alpine container_name: encar-redis restart: unless-stopped ports: - "127.0.0.1:6380:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 command: > redis-server --appendonly yes --save 60 1000 volumes: - encar_redisdata:/data logging: driver: json-file options: max-size: "10m" max-file: "5" # DB migrations migrate: <<: *app-service container_name: encar-migrate restart: "no" depends_on: postgres: condition: service_healthy command: alembic upgrade head # FastAPI api: <<: *app-service container_name: encar-api restart: unless-stopped ports: - "127.0.0.1:8001:8000" depends_on: migrate: condition: service_completed_successfully redis: condition: service_healthy command: > uvicorn encar_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: 20s stop_grace_period: 30s logging: driver: json-file options: max-size: "10m" max-file: "5" # Celery Worker (Encar — только HTTP API, без браузера) worker: <<: *app-service container_name: encar-worker restart: unless-stopped init: true depends_on: migrate: condition: service_completed_successfully redis: condition: service_healthy stop_grace_period: 30s command: > celery -A encar_scraper.worker.celery_app worker --loglevel=info --concurrency=4 --pool=prefork --pidfile=/tmp/celery-worker.pid -Q encar --max-tasks-per-child=50 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: 30s logging: driver: json-file options: max-size: "10m" max-file: "5" # Celery Beat (периодический планировщик) beat: <<: *app-service container_name: encar-beat restart: unless-stopped init: true depends_on: migrate: condition: service_completed_successfully redis: condition: service_healthy command: > celery -A encar_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: 30s logging: driver: json-file options: max-size: "10m" max-file: "5" volumes: encar_pgdata: encar_redisdata: