# Стратегия Управления Прокси и Аккаунтами В этом документе описывается интеллектуальная стратегия управления ресурсами (прокси и аккаунтами), используемая в `ytdlp-ops-server`. Цель этой системы — максимизировать процент успешных операций, минимизировать блокировки и обеспечить отказоустойчивость. Сервер может работать в разных ролях для поддержки распределенной архитектуры, разделяя задачи управления и задачи генерации токенов. --- ## Роли Сервиса и Архитектура Сервер предназначен для работы в одной из трех ролей, указываемых флагом `--service-role`: - **`management`**: Один легковесный экземпляр сервиса, отвечающий за все вызовы API управления. - **Назначение**: Предоставляет централизованную точку входа для мониторинга и управления состоянием всех прокси и аккаунтов в системе. - **Поведение**: Предоставляет только функции управления (`getProxyStatus`, `banAccount` и т.д.). Вызовы функций генерации токенов будут завершаться ошибкой. - **Развертывание**: Запускается как один контейнер (`ytdlp-ops-management`) и напрямую открывает свой порт на хост (например, порт `9091`), минуя Envoy. - **`worker`**: Основная "рабочая лошадка" для генерации токенов и `info.json`. - **Назначение**: Обрабатывает все запросы на генерацию токенов. - **Поведение**: Реализует полный API, но его функции управления ограничены его собственным `server_identity`. - **Развертывание**: Запускается как масштабируемый сервис (`ytdlp-ops-worker`) за балансировщиком нагрузки Envoy (например, порт `9080`). - **`all-in-one`** (По умолчанию): Один экземпляр, который выполняет как управленческие, так и рабочие функции. Идеально подходит для локальной разработки или небольших развертываний. Эта архитектура позволяет создать надежную, федеративную систему, где воркеры управляют своими ресурсами локально, в то время как центральный сервис предоставляет глобальное представление для управления и мониторинга. --- ## 1. Управление Жизненным Циклом Аккаунтов (Cooldown / Resting) **Цель:** Предотвратить чрезмерное использование и последующую блокировку аккаунтов, предоставляя им периоды "отдыха" после интенсивной работы. ### Как это работает: Жизненный цикл аккаунта состоит из трех состояний: - **`ACTIVE`**: Аккаунт активен и используется для выполнения задач. При первом успешном использовании запускается таймер его активности. - **`RESTING`**: Если аккаунт был в состоянии `ACTIVE` дольше установленного лимита, `AccountManager` автоматически переводит его в состояние "отдыха". В этом состоянии Airflow worker не будет выбирать его для новых задач. - **Возврат в `ACTIVE`**: После завершения периода "отдыха" `AccountManager` автоматически возвращает аккаунт в состояние `ACTIVE`, делая его снова доступным. ### Конфигурация: Эти параметры настраиваются при запуске `ytdlp-ops-server`. - `--account-active-duration-min`: "Время работы" в **минутах**, которое аккаунт может быть непрерывно активным до перехода в `RESTING`. - **Значение по умолчанию:** `30` (минут). - `--account-cooldown-duration-min`: "Время отдыха" в **минутах**, которое аккаунт должен находиться в состоянии `RESTING`. - **Значение по умолчанию:** `60` (минут). **Где настраивать:** Параметры передаются как аргументы командной строки при запуске сервера. При использовании Docker Compose это делается в файле `airflow/docker-compose-ytdlp-ops.yaml`: ```yaml command: # ... другие параметры - "--account-active-duration-min" - "${ACCOUNT_ACTIVE_DURATION_MIN:-30}" - "--account-cooldown-duration-min" - "${ACCOUNT_COOLDOWN_DURATION_MIN:-60}" ``` Вы можете изменить значения по умолчанию, установив переменные окружения `ACCOUNT_ACTIVE_DURATION_MIN` и `ACCOUNT_COOLDOWN_DURATION_MIN` в вашем `.env` файле. **Соответствующие файлы:** - `server_fix/account_manager.py`: Содержит основную логику для переключения состояний. - `ytdlp_ops_server_fix.py`: Обрабатывает аргументы командной строки. - `airflow/docker-compose-ytdlp-ops.yaml`: Передает аргументы в контейнер сервера. --- ## 2. Умная Стратегия Банов **Цель:** Избежать необоснованных банов хороших прокси. Проблема часто может быть в аккаунте, а не в прокси, через который он работает. ### Как это работает: #### Этап 1: Сначала Бан Аккаунта - При возникновении серьезной ошибки, требующей бана (например, `BOT_DETECTED` или `SOCKS5_CONNECTION_FAILED`), система применяет санкции **только к аккаунту**, который вызвал ошибку. - Для прокси эта ошибка просто фиксируется как один сбой, но сам прокси **не банится** и остается в работе. #### Этап 2: Бан Прокси по "Скользящему Окну" - Прокси блокируется автоматически, только если он демонстрирует **систематические сбои с РАЗНЫМИ аккаунтами** за короткий промежуток времени. - Это является надежным индикатором того, что проблема именно в прокси. `ProxyManager` на сервере отслеживает это и автоматически банит такой прокси. ### Конфигурация: Эти параметры **жестко заданы** как константы в коде и для их изменения требуется редактирование файла. **Где настраивать:** - **Файл:** `server_fix/proxy_manager.py` - **Константы** в классе `ProxyManager`: - `FAILURE_WINDOW_SECONDS`: Временное окно в секундах для анализа сбоев. - **Значение по умолчанию:** `3600` (1 час). - `FAILURE_THRESHOLD_COUNT`: Минимальное общее количество сбоев для запуска проверки. - **Значение по умолчанию:** `3`. - `FAILURE_THRESHOLD_UNIQUE_ACCOUNTS`: Минимальное количество **уникальных аккаунтов**, с которыми произошли сбои, чтобы забанить прокси. - **Значение по умолчанию:** `3`. **Соответствующие файлы:** - `server_fix/proxy_manager.py`: Содержит логику "скользящего окна" и константы. - `airflow/dags/ytdlp_ops_worker_per_url.py`: Функция `handle_bannable_error_callable` реализует политику бана "только аккаунт". --- ### Расшифровка Статусов Аккаунтов Вы можете просмотреть статус всех аккаунтов с помощью DAG `ytdlp_mgmt_proxy_account`. Статусы имеют следующие значения: - **`ACTIVE`**: Аккаунт исправен и доступен для использования. По умолчанию, аккаунт считается `ACTIVE`, если у него не установлен конкретный статус. - **`BANNED`**: Аккаунт временно отключен из-за повторяющихся сбоев (например, ошибок `BOT_DETECTED`) или забанен вручную. В статусе будет указано время, оставшееся до его автоматического возвращения в `ACTIVE` (например, `BANNED (active in 55m)`). - **`RESTING`**: Аккаунт использовался в течение длительного времени и находится в обязательном периоде "отдыха" для предотвращения "выгорания". В статусе будет указано время, оставшееся до его возвращения в `ACTIVE` (например, `RESTING (active in 25m)`). - **(Пустой Статус)**: В более старых версиях аккаунт, у которого были только сбои (и ни одного успеха), мог отображаться с пустым статусом. Это было исправлено; теперь такие аккаунты корректно отображаются как `ACTIVE`. --- ## 3. Сквозной Процесс Ротации: Как Всё Работает Вместе Этот раздел описывает пошаговый процесс того, как воркер получает аккаунт и прокси для одной задачи, объединяя все вышеописанные стратегии управления. 1. **Инициализация Воркера (`ytdlp_ops_worker_per_url`)** - Запускается DAG, инициированный либо оркестратором, либо предыдущим успешным запуском самого себя. - Задача `pull_url_from_redis` извлекает URL из очереди `_inbox` в Redis. 2. **Выбор Аккаунта (Воркер Airflow)** - Выполняется задача `assign_account`. - Она генерирует полный список потенциальных ID аккаунтов на основе параметра `account_pool` (например, от `my_prefix_01` до `my_prefix_50`). - Она подключается к Redis и проверяет статус каждого аккаунта из этого списка. - Она создает новый временный список, содержащий только те аккаунты, которые **не** находятся в состоянии `BANNED` или `RESTING`. - Если итоговый список активных аккаунтов пуст, воркер завершается с ошибкой (если не включено автосоздание). - Затем из отфильтрованного списка активных аккаунтов с помощью **`random.choice()`** выбирается один. - Выбранный `account_id` передается следующей задаче. 3. **Выбор Прокси (`ytdlp-ops-server`)** - Выполняется задача `get_token`, которая отправляет случайно выбранный `account_id` в Thrift RPC-вызове на `ytdlp-ops-server`. - На сервере у `ProxyManager` запрашивается прокси. - `ProxyManager`: a. Обновляет свое внутреннее состояние, загружая статусы всех прокси из Redis. b. Фильтрует список, оставляя только прокси со статусом `ACTIVE`. c. Применяет политику бана по "скользящему окну", потенциально блокируя прокси, которые недавно слишком часто выходили из строя. d. Выбирает следующий доступный прокси из активного списка, используя индекс **round-robin** (по кругу). e. Возвращает выбранный `proxy_url`. 4. **Выполнение и Отчетность** - Теперь у сервера есть и `account_id` (от Airflow), и `proxy_url` (от его `ProxyManager`). - Он приступает к процессу генерации токенов, используя эти ресурсы. - По завершении (успешном или неудачном) он сообщает о результате в Redis, обновляя статусы для конкретного аккаунта и прокси, которые были использованы. Это влияет на их счетчики сбоев, таймеры "отдыха" и т.д. для следующего запуска. Это разделение ответственности является ключевым: - **Воркер Airflow (задача `assign_account`)** отвечает за **случайный выбор активного аккаунта**, сохраняя при этом "привязку" (повторно используя тот же аккаунт после успеха). - **Сервер `ytdlp-ops-server`** отвечает за **циклический выбор (round-robin) активного прокси**. --- ## 4. Автоматический Бан Аккаунтов по Количеству Сбоев **Цель:** Автоматически выводить из ротации аккаунты, которые постоянно вызывают ошибки, не связанные с баном (например, неверный пароль, проблемы с авторизацией). ### Как это работает: - `AccountManager` отслеживает количество **последовательных** сбоев для каждого аккаунта. - При успешной операции счетчик сбрасывается. - Если количество последовательных сбоев достигает заданного порога, аккаунт автоматически банится на определенный срок. ### Конфигурация: Эти параметры задаются в конструкторе класса `AccountManager`. **Где настраивать:** - **Файл:** `server_fix/account_manager.py` - **Параметры** в `__init__` метода `AccountManager`: - `failure_threshold`: Количество последовательных сбоев до бана. - **Значение по умолчанию:** `5`. - `ban_duration_s`: Длительность бана в секундах. - **Значение по умолчанию:** `3600` (1 час). --- ## 5. Мониторинг и Восстановление ### Как Проверить Статусы DAG **`ytdlp_mgmt_proxy_account`** — это основной инструмент для мониторинга состояния ваших ресурсов. Он подключается напрямую к **сервису управления** для выполнения действий. - **ID DAG'а:** `ytdlp_mgmt_proxy_account` - **Как использовать:** Запустите DAG из интерфейса Airflow. Убедитесь, что параметры `management_host` и `management_port` правильно указывают на ваш экземпляр сервиса `ytdlp-ops-management`. Для получения полного обзора установите параметры: - `entity`: `all` - `action`: `list` - **Результат:** В логе DAG'а будут отображены таблицы с текущим статусом всех аккаунтов и прокси. Для аккаунтов в состоянии `BANNED` или `RESTING` будет показано время, оставшееся до их активации (например, `RESTING (active in 45m)`). Для прокси будет подсвечено, какой из них является следующим `(next)` в ротации для конкретного воркера. ### Что Произойдет, если Все Аккаунты Будут Забанены или в "Отдыхе"? Если весь пул аккаунтов станет недоступен (в статусе `BANNED` или `RESTING`), система по умолчанию приостановит работу. - DAG `ytdlp_ops_worker_per_url` завершится с ошибкой `AirflowException` на шаге `assign_account`, так как пул активных аккаунтов будет пуст. - Это остановит циклы обработки. Система будет находиться в состоянии паузы до тех пор, пока аккаунты не будут разбанены вручную или пока не истечет их таймер бана/отдыха. После этого вы сможете перезапустить циклы обработки с помощью DAG'а `ytdlp_ops_orchestrator`. - Граф выполнения DAG `ytdlp_ops_worker_per_url` теперь явно показывает такие задачи, как `assign_account`, `get_token`, `ban_account`, `retry_get_token` и т.д., что делает поток выполнения и точки сбоя более наглядными. Систему можно настроить на автоматическое создание новых аккаунтов, чтобы предотвратить полную остановку обработки. #### Автоматическое Создание Аккаунтов при Исчерпании - **Цель**: Обеспечить непрерывную работу конвейера обработки, даже если все аккаунты в основном пуле временно забанены или находятся в "отдыхе". - **Как это работает**: Если параметр `auto_create_new_accounts_on_exhaustion` установлен в `True` и пул аккаунтов задан с помощью префикса (а не явного списка), система сгенерирует новый уникальный ID аккаунта, когда обнаружит, что активный пул пуст. - **Именование новых аккаунтов**: Новые аккаунты создаются в формате `{prefix}-auto-{уникальный_id}`. - **Конфигурация**: - **Параметр**: `auto_create_new_accounts_on_exhaustion` - **Где настраивать**: В конфигурации DAG `ytdlp_ops_orchestrator` при запуске. - **Значение по умолчанию**: `True`. --- ## 6. Обработка Сбоев и Политика Повторных Попыток **Цель:** Обеспечить гибкое управление поведением системы, когда воркер сталкивается с ошибкой, требующей бана (например, `BOT_DETECTED`). ### Как это работает Когда задача `get_token` воркера завершается с ошибкой, требующей бана, поведение системы определяется политикой `on_bannable_failure`, которую можно настроить при запуске `ytdlp_ops_orchestrator`. ### Конфигурация - **Параметр**: `on_bannable_failure` - **Где настраивать**: В конфигурации DAG `ytdlp_ops_orchestrator`. - **Опции**: - `stop_loop` (Самая строгая): - Использованный аккаунт банится. - URL помечается как сбойный в хэше `_fail` в Redis. - Цикл обработки воркера **останавливается**. "Линия" обработки становится неактивной. - `retry_with_new_account` (По умолчанию, самая отказоустойчивая): - Аккаунт, вызвавший сбой, банится. - Воркер немедленно повторяет обработку **того же URL** с новым, неиспользованным аккаунтом из пула. - Если повторная попытка успешна, воркер продолжает свой цикл для обработки следующего URL. - Если повторная попытка также завершается сбоем, второй аккаунт **и использованный прокси** также банятся, и цикл работы воркера останавливается. - `retry_and_ban_account_only`: - Похожа на `retry_with_new_account`, но при втором сбое банится **только второй аккаунт**, а не прокси. - Это полезно, когда вы доверяете своим прокси, но хотите агрессивно перебирать сбойные аккаунты. - `retry_without_ban` (Самая мягкая): - Воркер повторяет попытку с новым аккаунтом, но **ни аккаунты, ни прокси никогда не банятся**. - Эта политика полезна для отладки или когда вы уверены, что сбои являются временными и не вызваны проблемами с ресурсами. Эта политика позволяет системе быть устойчивой к сбоям отдельных аккаунтов, не теряя URL, и в то же время обеспечивает гранулярный контроль над тем, когда банить аккаунты и/или прокси, если проблема сохраняется. --- ## 7. Логика Работы Worker DAG (`ytdlp_ops_worker_per_url`) Этот DAG является "рабочей лошадкой" системы. Он спроектирован как самоподдерживающийся цикл для обработки одного URL за запуск. Логика обработки сбоев и повторных попыток теперь явно видна в графе задач DAG. ### Задачи и их назначение: - **`pull_url_from_redis`**: Извлекает один URL из очереди `_inbox` в Redis. Если очередь пуста, DAG завершается со статусом `skipped`, останавливая эту "линию" обработки. - **`assign_account`**: Выбирает аккаунт для задачи. Он поддерживает **привязку аккаунта (affinity)**, повторно используя тот же аккаунт из предыдущего успешного запуска в своей "линии". Если это первый запуск или предыдущий был неудачным, он выбирает случайный активный аккаунт. - **`get_token`**: Основная попытка получить токены и `info.json` путем вызова `ytdlp-ops-server`. - **`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`), остановить его корректно (`stop_loop`) или пометить как сбойный (`fail_loop`). - **`trigger_self_run`**: Задача, которая фактически запускает следующий экземпляр DAG, создавая непрерывный цикл.