From 2786f5ba72dbfc24235d209ddbf1ad7e600aaafa Mon Sep 17 00:00:00 2001 From: aperez Date: Wed, 17 Sep 2025 12:04:11 +0300 Subject: [PATCH] Some updates, mostly problems with postgres permissions and logs permissions, mess with improper master management service processing from .env --- airflow/configs/.env.master | 39 ++++- airflow/configs/docker-compose-master.yaml.j2 | 1 + .../configs/docker-compose-ytdlp-ops.yaml.j2 | 4 +- .../docker-compose.config-generate.yaml | 2 +- airflow/dags/ORCHESTRATOR.ru.md | 135 ++++++++++++++++++ airflow/generate_envoy_config.py | 29 +++- ansible/group_vars/all/generated_vars.yml | 2 +- ansible/host_vars/af-green.yml | 22 +++ ansible/host_vars/dl001.yml | 22 +++ ansible/host_vars/dl003.yml | 22 +++ ansible/inventory.ini | 5 +- ansible/roles/ytdlp-master/tasks/main.yml | 1 + ansible/templates/.env.j2 | 62 ++++---- cluster.green.yml | 2 +- 14 files changed, 301 insertions(+), 47 deletions(-) create mode 100644 airflow/dags/ORCHESTRATOR.ru.md create mode 100644 ansible/host_vars/af-green.yml create mode 100644 ansible/host_vars/dl001.yml create mode 100644 ansible/host_vars/dl003.yml diff --git a/airflow/configs/.env.master b/airflow/configs/.env.master index 9288246..1f848ab 100644 --- a/airflow/configs/.env.master +++ b/airflow/configs/.env.master @@ -1,4 +1,35 @@ -# This file should be generated from ansible/templates/.env.ytdlp.j2 -# Do not edit manually - your changes will be overwritten. -# -# To generate this file, run the Ansible playbook that processes the templates. +# This file is managed by Ansible. Do not edit manually. + +# --- Common Settings --- +HOSTNAME="af-green" +COMPOSE_PROJECT_NAME="ytdlp-ops-management" +TZ="Europe/Moscow" +service_role="management" + +# --- Docker Image Settings --- +YTDLP_OPS_IMAGE="pangramia/ytdlp-ops-server:latest" +AIRFLOW_IMAGE_NAME="pangramia/ytdlp-ops-airflow:latest" + +# --- Network Settings --- +ENVOY_PORT=9080 +ENVOY_ADMIN_PORT=9901 +YTDLP_BASE_PORT=9090 +YTDLP_WORKERS=3 +MANAGEMENT_SERVICE_PORT=9091 +REDIS_PORT=52909 +POSTGRES_PORT=5432 + +# --- Security Settings --- +REDIS_PASSWORD="rOhTAIlTFFylXsjhqwxnYxDChFc" +POSTGRES_PASSWORD="pgdb_pwd_A7bC2xY9zE1wV5uP" +AIRFLOW_ADMIN_PASSWORD="2r234sdfrt3q454arq45q355" +FLOWER_PASSWORD="dO4eXm7UkF81OdMvT8E2tIKFtPYPCzyzwlcZ4RyOmCsmG4qzrNFqM5sNTOT9" + +# --- User and Group IDs --- +AIRFLOW_UID=1003 +AIRFLOW_GID=1001 + +# --- Master-specific settings --- +MASTER_HOST_IP=89.253.221.173 +# Camoufox is not used on master, but the config generator expects the variable. +CAMOUFOX_PROXIES= diff --git a/airflow/configs/docker-compose-master.yaml.j2 b/airflow/configs/docker-compose-master.yaml.j2 index 35419cb..4954bc6 100644 --- a/airflow/configs/docker-compose-master.yaml.j2 +++ b/airflow/configs/docker-compose-master.yaml.j2 @@ -149,6 +149,7 @@ services: retries: 5 start_period: 5s restart: always + user: "999:999" redis: # Redis is limited to 7.2-bookworm due to licencing change diff --git a/airflow/configs/docker-compose-ytdlp-ops.yaml.j2 b/airflow/configs/docker-compose-ytdlp-ops.yaml.j2 index 98007cd..574d550 100644 --- a/airflow/configs/docker-compose-ytdlp-ops.yaml.j2 +++ b/airflow/configs/docker-compose-ytdlp-ops.yaml.j2 @@ -78,7 +78,7 @@ services: - "--service-role" - "{{ service_role }}" -{% if service_role != 'management' %} +{% if service_role is defined and service_role != 'management' %} # --- Parameters for worker/all-in-one roles ONLY --- - "--script-dir" - "/app" @@ -100,9 +100,7 @@ services: volumes: context-data: -{% if service_role == 'management' or not camoufox_proxies %} networks: proxynet: name: airflow_proxynet external: true -{% endif %} diff --git a/airflow/configs/docker-compose.config-generate.yaml b/airflow/configs/docker-compose.config-generate.yaml index 42ea4ea..46a3b85 100644 --- a/airflow/configs/docker-compose.config-generate.yaml +++ b/airflow/configs/docker-compose.config-generate.yaml @@ -8,6 +8,6 @@ services: - ./.env volumes: # Mount the entire project directory to access scripts and write output files - - ../:/app + - .:/app command: > sh -c "pip install jinja2 && python3 /app/generate_envoy_config.py" diff --git a/airflow/dags/ORCHESTRATOR.ru.md b/airflow/dags/ORCHESTRATOR.ru.md new file mode 100644 index 0000000..72a203e --- /dev/null +++ b/airflow/dags/ORCHESTRATOR.ru.md @@ -0,0 +1,135 @@ +# Архитектура и описание YTDLP Airflow DAGs + +Этот документ описывает архитектуру и назначение DAG'ов, используемых для скачивания видео с YouTube. Система построена на модели непрерывного, самоподдерживающегося цикла для параллельной и отказоустойчивой обработки. + +## Основной цикл обработки + +Обработка выполняется двумя основными DAG'ами, которые работают в паре: оркестратор и воркер. + +### `ytdlp_ops_orchestrator` (Система "зажигания") + +- **Назначение:** Этот DAG действует как "система зажигания" для запуска обработки. Он запускается вручную для старта указанного количества параллельных циклов-воркеров. +- **Принцип работы:** + - Он **не** обрабатывает URL-адреса самостоятельно. + - Его единственная задача — запустить сконфигурированное количество DAG'ов `ytdlp_ops_worker_per_url`. + - Он передает всю необходимую конфигурацию (пул аккаунтов, подключение к Redis и т.д.) воркерам. + +### `ytdlp_ops_worker_per_url` (Самоподдерживающийся воркер) + +- **Назначение:** Этот DAG обрабатывает один URL и спроектирован для работы в непрерывном цикле. +- **Принцип работы:** + 1. **Запуск:** Начальный запуск инициируется `ytdlp_ops_orchestrator`. + 2. **Получение задачи:** Воркер извлекает один URL из очереди `_inbox` в Redis. Если очередь пуста, выполнение воркера завершается, и его "линия" обработки останавливается. + 3. **Обработка:** Он взаимодействует с сервисом `ytdlp-ops-server` для получения `info.json` и прокси, после чего скачивает видео. + 4. **Продолжение или остановка:** + - **В случае успеха:** Он запускает новый экземпляр самого себя, создавая непрерывный цикл для обработки следующего URL. + - **В случае сбоя:** Цикл прерывается (если `stop_on_failure` установлено в `True`), останавливая эту "линию" обработки. Это предотвращает остановку всей системы из-за одного проблемного URL или аккаунта. + +## Управляющие DAG'и + +### `ytdlp_mgmt_proxy_account` + +- **Назначение:** Это основной инструмент для мониторинга и управления состоянием ресурсов, используемых `ytdlp-ops-server`. +- **Функциональность:** + - **Просмотр статусов:** Позволяет увидеть текущий статус всех прокси и аккаунтов (например, `ACTIVE`, `BANNED`, `RESTING`). + - **Управление прокси:** Позволяет вручную банить, разбанивать или сбрасывать статус прокси. + - **Управление аккаунтами:** Позволяет вручную банить или разбанивать аккаунты. + +### `ytdlp_mgmt_queues` + +- **Назначение:** Предоставляет набор инструментов для управления очередями Redis, используемыми в конвейере обработки. +- **Функциональность (через параметр `action`):** + - `add_videos`: Добавление одного или нескольких URL-адресов YouTube в очередь. + - `clear_queue`: Очистка (удаление) указанного ключа Redis. + - `list_contents`: Просмотр содержимого ключа Redis (списка или хэша). + - `check_status`: Проверка общего состояния очередей (тип, размер). + - `requeue_failed`: Перемещение всех URL-адресов из очереди сбоев `_fail` обратно в очередь `_inbox` для повторной обработки. + +## Стратегия управления ресурсами (Прокси и Аккаунты) + +Система использует интеллектуальную стратегию для управления жизненным циклом и состоянием аккаунтов и прокси, чтобы максимизировать процент успеха и минимизировать блокировки. + +- **Жизненный цикл аккаунта ("Cooldown"):** + - Чтобы предотвратить "выгорание", аккаунты автоматически переходят в состояние "отдыха" (`RESTING`) после периода интенсивного использования. + - По истечении периода отдыха они автоматически возвращаются в `ACTIVE` и снова становятся доступными для воркеров. + +- **Умная стратегия банов:** + - **Сначала бан аккаунта:** При возникновении серьезной ошибки (например, `BOT_DETECTED`) система наказывает **только аккаунт**, который вызвал сбой. Прокси при этом продолжает работать. + - **Бан прокси по "скользящему окну":** Прокси банится автоматически, только если он демонстрирует **систематические сбои с РАЗНЫМИ аккаунтами** за короткий промежуток времени. Это является надежным индикатором того, что проблема именно в прокси. + +- **Мониторинг:** + - DAG `ytdlp_mgmt_proxy_account` является основным инструментом для мониторинга. Он показывает текущий статус всех ресурсов, включая время, оставшееся до активации забаненных или отдыхающих аккаунтов. + - Граф выполнения DAG `ytdlp_ops_worker_per_url` теперь явно показывает шаги, такие как `assign_account`, `get_token`, `ban_account`, `retry_get_token`, что делает процесс отладки более наглядным. + +## Внешние сервисы + +### `ytdlp-ops-server` (Thrift Service) + +- **Назначение:** Внешний сервис, который предоставляет аутентификационные данные (токены, cookies, proxy) для скачивания видео. +- **Взаимодействие:** Worker DAG (`ytdlp_ops_worker_per_url`) обращается к этому сервису перед началом загрузки для получения необходимых данных для `yt-dlp`. + +## Логика работы Worker DAG (`ytdlp_ops_worker_per_url`) + +Этот DAG является "рабочей лошадкой" системы. Он спроектирован как самоподдерживающийся цикл для обработки одного URL за запуск. + +### Задачи и их назначение: + +- **`pull_url_from_redis`**: Извлекает один URL из очереди `_inbox` в Redis. Если очередь пуста, DAG завершается со статусом `skipped`, останавливая эту "линию" обработки. +- **`assign_account`**: Выбирает аккаунт для выполнения задачи. Он будет повторно использовать тот же аккаунт, который был успешно использован в предыдущем запуске в своей "линии" (привязка аккаунта). Если это первый запуск, он выбирает случайный аккаунт. +- **`get_token`**: Основная задача. Она обращается к `ytdlp-ops-server` для получения `info.json`. +- **`handle_bannable_error_branch`**: Если `get_token` завершается с ошибкой, требующей бана, эта задача-развилка решает, что делать дальше, в зависимости от политики `on_bannable_failure`. +- **`ban_account_and_prepare_for_retry`**: Если политика разрешает повтор, эта задача банит сбойный аккаунт и выбирает новый для повторной попытки. +- **`retry_get_token`**: Выполняет вторую попытку получить токен с новым аккаунтом. +- **`ban_second_account_and_proxy`**: Если и вторая попытка неудачна, эта задача банит второй аккаунт и использованный прокси. +- **`download_and_probe`**: Если `get_token` (или `retry_get_token`) завершилась успешно, эта задача использует `yt-dlp` для скачивания медиа и `ffmpeg` для проверки целостности скачанного файла. +- **`mark_url_as_success`**: Если `download_and_probe` завершилась успешно, эта задача записывает результат в хэш `_result` в Redis. +- **`handle_generic_failure`**: Если любая из основных задач завершается с неисправимой ошибкой, эта задача записывает подробную информацию об ошибке в хэш `_fail` в Redis. +- **`decide_what_to_do_next`**: Задача-развилка, которая запускается после успеха или неудачи. Она решает, продолжать ли цикл. +- **`trigger_self_run`**: Задача, которая фактически запускает следующий экземпляр DAG, создавая непрерывный цикл. + +## Механизм привязки воркеров к конкретным машинам (Worker Pinning / Affinity) + +Для обеспечения того, чтобы все задачи, связанные с обработкой одного конкретного URL, выполнялись на одной и той же машине (воркере), система использует комбинацию из трех компонентов: Оркестратора, Диспетчера и специального хука Airflow. + +### 1. `ytdlp_ops_orchestrator` (Оркестратор) + +- **Роль:** Инициирует процесс обработки. +- **Действие:** При запуске он создает несколько DAG-запусков `ytdlp_ops_dispatcher`. Каждый такой запуск предназначен для обработки одного URL. +- **Передача параметров:** Оркестратор передает свои параметры конфигурации (например, `account_pool`, `redis_conn_id`, `service_ip`) каждому запуску диспетчера. + +### 2. `ytdlp_ops_dispatcher` (Диспетчер) + +- **Роль:** Основной механизм обеспечения привязки. +- **Действие:** + 1. **Получает URL:** Извлекает один URL из очереди Redis (`_inbox`). + 2. **Определяет воркер:** Использует `socket.gethostname()` для определения имени текущей машины (воркера), на которой он выполняется. + 3. **Формирует имя очереди:** Создает уникальное имя очереди для этого воркера, например, `queue-dl-dl-worker-1`. + 4. **Запускает Worker DAG:** Инициирует запуск DAG `ytdlp_ops_worker_per_url`, передавая ему: + * Извлеченный `url_to_process`. + * Сформированное имя очереди `worker_queue` через параметр `conf`. + * Все остальные параметры, полученные от оркестратора. +- **Ключевой момент:** Именно на этом этапе устанавливается связь между конкретным URL и конкретным воркером, на котором началась обработка этого URL. + +### 3. `task_instance_mutation_hook` (Хук изменения задач) + +- **Расположение:** `airflow/config/custom_task_hooks.py` +- **Роль:** Является механизмом, который обеспечивает выполнение *всех* задач Worker DAG на нужной машине. +- **Как это работает:** + 1. **Регистрация:** Хук регистрируется в конфигурации Airflow и вызывается перед запуском *каждой* задачи. + 2. **Проверка DAG ID:** Хук проверяет, принадлежит ли задача (`TaskInstance`) DAG `ytdlp_ops_worker_per_url`. + 3. **Извлечение `conf`:** Если да, он безопасно извлекает `conf` из `DagRun`, связанного с этой задачей. + 4. **Изменение очереди:** + * Если в `conf` найден ключ `worker_queue` (что будет true для всех запусков, инициированных диспетчером), хук *переопределяет* стандартную очередь задачи на это значение. + * Это означает, что Airflow планировщик поставит эту задачу именно в ту очередь, которая прослушивается нужным воркером. + 5. **Резервный вариант:** Если `worker_queue` не найден (например, DAG запущен вручную), задача возвращается в стандартную очередь `queue-dl`. +- **Ключевой момент:** Этот хук гарантирует, что *все последующие задачи* в рамках одного запуска `ytdlp_ops_worker_per_url` (например, `get_token`, `download_and_probe`, `mark_url_as_success`) будут выполнены на том же воркере, который изначально получил URL в диспетчере. + +### Резюме + +Комбинация `Оркестратор -> Диспетчер -> Хук` эффективно реализует привязку задач к воркерам: + +1. **Оркестратор** запускает процесс. +2. **Диспетчер** связывает конкретный URL с конкретным воркером, определяя его имя хоста и передавая его как `worker_queue` в Worker DAG. +3. **Хук** гарантирует, что все задачи Worker DAG выполняются в очереди, соответствующей этому воркеру. + +Это позволяет системе использовать локальные ресурсы воркера (например, кэш, временные файлы) эффективно и предсказуемо для обработки каждого отдельного URL. diff --git a/airflow/generate_envoy_config.py b/airflow/generate_envoy_config.py index ff446c3..5c1a28e 100644 --- a/airflow/generate_envoy_config.py +++ b/airflow/generate_envoy_config.py @@ -33,7 +33,7 @@ def load_dotenv(dotenv_path): """ if not os.path.exists(dotenv_path): logging.warning(f".env file not found at {dotenv_path}. Using system environment variables or defaults.") - return + return False try: with open(dotenv_path) as f: for line in f: @@ -43,6 +43,7 @@ def load_dotenv(dotenv_path): key = key.strip() value = value.strip() # Remove surrounding quotes which are common in .env files + # Handle both single and double quotes if (value.startswith('"') and value.endswith('"')) or \ (value.startswith("'") and value.endswith("'")): value = value[1:-1] @@ -53,9 +54,10 @@ def load_dotenv(dotenv_path): if key not in os.environ: os.environ[key] = value logging.info(f"Successfully loaded variables from {dotenv_path}") + return True except Exception as e: logging.error(f"Failed to read or parse {dotenv_path}: {e}") - # Continue, will use defaults or system env vars + return False def _get_port_from_proxy_url(url: str) -> Optional[str]: """Extracts the port from a proxy URL string.""" @@ -94,9 +96,18 @@ def generate_configs(): project_root = os.path.dirname(os.path.abspath(__file__)) # This will be /app configs_dir = os.path.join(project_root, 'configs') - # Load .env from the 'configs' directory. - dotenv_path = os.path.join(configs_dir, '.env') - load_dotenv(dotenv_path) + # Load .env from the project root ONLY - no fallback + dotenv_path = os.path.join(project_root, '.env') + logging.info(f"Looking for .env file at: {dotenv_path}") + + if os.path.exists(dotenv_path): + if load_dotenv(dotenv_path): + logging.info(f"Using .env file from: {dotenv_path}") + else: + logging.error(f"Failed to load .env file from: {dotenv_path}") + exit(1) + else: + logging.warning(f".env file not found at {dotenv_path}. Using system environment variables or defaults.") # --- Common Configuration --- ytdlp_workers_str = os.getenv('YTDLP_WORKERS', '3').strip() @@ -117,7 +128,13 @@ def generate_configs(): env.globals['_get_port_from_proxy_url'] = _get_port_from_proxy_url # Get service role from environment to determine what to generate - service_role = os.getenv('SERVICE_ROLE', 'all-in-one') + # Ensure we strip any remaining quotes that might have slipped through + service_role = os.getenv('service_role', 'management') + # Additional stripping of quotes for robustness + if (service_role.startswith('"') and service_role.endswith('"')) or \ + (service_role.startswith("'") and service_role.endswith("'")): + service_role = service_role[1:-1] + logging.info(f"Service role for generation: '{service_role}'") # --- Camoufox Configuration (only for worker/all-in-one roles) --- diff --git a/ansible/group_vars/all/generated_vars.yml b/ansible/group_vars/all/generated_vars.yml index 79a77f2..3052d31 100644 --- a/ansible/group_vars/all/generated_vars.yml +++ b/ansible/group_vars/all/generated_vars.yml @@ -17,7 +17,7 @@ external_access_ips: [] file_permissions: '0644' host_timezone: Europe/Moscow management_service_port: 9091 -master_host_ip: 89.253.223.97 +master_host_ip: 89.253.221.173 postgres_port: 5432 redis_port: 52909 rsync_default_opts: diff --git a/ansible/host_vars/af-green.yml b/ansible/host_vars/af-green.yml new file mode 100644 index 0000000..dbd71d6 --- /dev/null +++ b/ansible/host_vars/af-green.yml @@ -0,0 +1,22 @@ +--- +# Variables for af-green +master_host_ip: 89.253.221.173 +redis_port: 52909 +shadowsocks_proxies: + sslocal-rust-1087: + server: "91.103.252.51" + server_port: 8388 + local_port: 1087 + vault_password_key: "vault_ss_password_1" + sslocal-rust-1086: + server: "62.60.178.45" + server_port: 8388 + local_port: 1086 + vault_password_key: "vault_ss_password_2" + sslocal-rust-1081: + server: "79.137.207.43" + server_port: 8388 + local_port: 1081 + vault_password_key: "vault_ss_password_2" +worker_proxies: + - "socks5://sslocal-rust-1087:1087" diff --git a/ansible/host_vars/dl001.yml b/ansible/host_vars/dl001.yml new file mode 100644 index 0000000..c09444a --- /dev/null +++ b/ansible/host_vars/dl001.yml @@ -0,0 +1,22 @@ +--- +# Variables for dl001 +master_host_ip: 89.253.221.173 +redis_port: 52909 +shadowsocks_proxies: + sslocal-rust-1087: + server: "91.103.252.51" + server_port: 8388 + local_port: 1087 + vault_password_key: "vault_ss_password_1" + sslocal-rust-1086: + server: "62.60.178.45" + server_port: 8388 + local_port: 1086 + vault_password_key: "vault_ss_password_2" + sslocal-rust-1081: + server: "79.137.207.43" + server_port: 8388 + local_port: 1081 + vault_password_key: "vault_ss_password_2" +worker_proxies: + - "socks5://sslocal-rust-1087:1087" diff --git a/ansible/host_vars/dl003.yml b/ansible/host_vars/dl003.yml new file mode 100644 index 0000000..0133cb1 --- /dev/null +++ b/ansible/host_vars/dl003.yml @@ -0,0 +1,22 @@ +--- +# Variables for dl003 +master_host_ip: 89.253.221.173 +redis_port: 52909 +shadowsocks_proxies: + sslocal-rust-1087: + server: "91.103.252.51" + server_port: 8388 + local_port: 1087 + vault_password_key: "vault_ss_password_1" + sslocal-rust-1086: + server: "62.60.178.45" + server_port: 8388 + local_port: 1086 + vault_password_key: "vault_ss_password_2" + sslocal-rust-1081: + server: "79.137.207.43" + server_port: 8388 + local_port: 1081 + vault_password_key: "vault_ss_password_2" +worker_proxies: + - "socks5://sslocal-rust-1087:1087" diff --git a/ansible/inventory.ini b/ansible/inventory.ini index 1be33c6..02fec51 100644 --- a/ansible/inventory.ini +++ b/ansible/inventory.ini @@ -3,7 +3,8 @@ # Edit cluster.yml and re-run the generator instead. [airflow_master] -af-test ansible_host=89.253.223.97 ansible_port=22 +af-green ansible_host=89.253.221.173 ansible_port=22 [airflow_workers] -dl002 ansible_host=62.60.178.54 +dl003 ansible_host=62.60.245.103 +dl001 ansible_host=109.107.189.106 diff --git a/ansible/roles/ytdlp-master/tasks/main.yml b/ansible/roles/ytdlp-master/tasks/main.yml index 04d8d8b..e2f7037 100644 --- a/ansible/roles/ytdlp-master/tasks/main.yml +++ b/ansible/roles/ytdlp-master/tasks/main.yml @@ -47,6 +47,7 @@ - "docker-compose-ytdlp-ops.yaml.j2" - "docker-compose.config-generate.yaml" - "envoy.yaml.j2" + - "docker-compose.camoufox.yaml.j2" - name: Create .env file for YT-DLP master service template: diff --git a/ansible/templates/.env.j2 b/ansible/templates/.env.j2 index 91e117a..f99cdeb 100644 --- a/ansible/templates/.env.j2 +++ b/ansible/templates/.env.j2 @@ -1,55 +1,59 @@ -# This file is managed by Ansible. -# Set the timezone for all services to ensure consistency in logs. -TZ=Europe/Moscow +# This file is managed by Ansible. Do not edit manually. +# --- Common Settings --- HOSTNAME="{{ inventory_hostname }}" -SERVICE_ROLE={{ service_role }} -{% if server_identity is defined %} -SERVER_IDENTITY={{ server_identity }} -{% endif %} +COMPOSE_PROJECT_NAME="ytdlp-ops-{{ service_role | default('all-in-one') }}" +TZ="{{ host_timezone }}" +service_role={{ service_role | default('all-in-one') }} -# Passwords +# --- Docker Image Settings --- +YTDLP_OPS_IMAGE="{{ ytdlp_ops_image }}" +AIRFLOW_IMAGE_NAME="{{ airflow_image_name }}" + +# --- Network Settings --- +ENVOY_PORT={{ envoy_port }} +ENVOY_ADMIN_PORT={{ envoy_admin_port }} +YTDLP_BASE_PORT={{ ytdlp_base_port }} +YTDLP_WORKERS={{ ytdlp_workers | default(3) }} +MANAGEMENT_SERVICE_PORT={{ management_service_port }} +REDIS_PORT={{ redis_port }} +POSTGRES_PORT={{ postgres_port }} + +# --- Security Settings --- REDIS_PASSWORD="{{ vault_redis_password }}" POSTGRES_PASSWORD="{{ vault_postgres_password }}" - -# Common settings -AIRFLOW_UID={{ airflow_uid | default(1003) }} -AIRFLOW_GID={{ deploy_group_gid | default(1001) }} -YTDLP_BASE_PORT={{ ytdlp_base_port }} -REDIS_PORT={{ redis_port }} - -# Master-specific settings -{% if 'master' in service_role or 'management' in service_role %} AIRFLOW_ADMIN_PASSWORD="{{ vault_airflow_admin_password }}" FLOWER_PASSWORD="{{ vault_flower_password }}" -AIRFLOW_VAR_MASTER_HOST_IP={{ hostvars[groups['airflow_master'][0]].ansible_host }} -# MASTER_HOST_IP is not needed on the master node itself for ytdlp-ops, -# as it connects to Redis via the internal Docker service name 'redis'. -# It is defined for workers to connect back to the master. + +# --- User and Group IDs --- +AIRFLOW_UID={{ airflow_uid | default(1003) }} +AIRFLOW_GID={{ deploy_group_gid | default(1001) }} + +# --- Master-specific settings --- +{% if 'master' in service_role or 'management' in service_role %} +MASTER_HOST_IP={{ hostvars[groups['airflow_master'][0]].ansible_host }} # Camoufox is not used on master, but the config generator expects the variable. CAMOUFOX_PROXIES= {% endif %} -# Worker-specific settings +# --- Worker-specific settings --- {% if 'worker' in service_role %} AIRFLOW_PROJ_DIR={{ airflow_worker_dir }} MASTER_HOST_IP={{ hostvars[groups['airflow_master'][0]].ansible_host }} # --- Envoy & Worker Configuration --- -ENVOY_PORT={{ envoy_port }} -ENVOY_ADMIN_PORT={{ envoy_admin_port }} -MANAGEMENT_SERVICE_PORT={{ management_service_port }} -YTDLP_WORKERS=4 +ENVOY_BACKEND_ADDRESS=ytdlp-ops-service +YTDLP_TIMEOUT=600 # --- Camoufox (Browser) Configuration --- CAMOUFOX_PROXIES="{{ (worker_proxies | default([])) | join(',') }}" VNC_PASSWORD="{{ vault_vnc_password }}" CAMOUFOX_BASE_VNC_PORT={{ camoufox_base_vnc_port }} -CAMOUFOX_PORT=12345 +CAMOUFOX_PORT={{ camoufox_port }} # --- Account Manager Configuration --- -ACCOUNT_ACTIVE_DURATION_MIN=7 -ACCOUNT_COOLDOWN_DURATION_MIN=30 +ACCOUNT_ACTIVE_DURATION_MIN={{ account_active_duration_min | default(7) }} +ACCOUNT_COOLDOWN_DURATION_MIN={{ account_cooldown_duration_min | default(30) }} {% endif %} diff --git a/cluster.green.yml b/cluster.green.yml index f9818c6..4eb54c7 100644 --- a/cluster.green.yml +++ b/cluster.green.yml @@ -88,7 +88,7 @@ shadowsocks_proxies: master: af-green: - ip: 89.253.223.97 + ip: 89.253.221.173 port: 22 proxies: - "socks5://sslocal-rust-1087:1087"