Files
av-parser/docs/proxies.md
T
Leonid Pershin eb5061ee23 Refactor media source handling and update collection options
- Updated `IMediaSourceCatalog` to support user-added media sources, allowing dynamic editing and management of sources.
- Removed the `UrlListSource` class as its functionality is now integrated into the new catalog structure.
- Enhanced `CollectOptions` to default `RequireProxy` to true, ensuring stricter handling of proxy requirements.
- Improved error handling in `ParseError` to include a `Subject` field for better context on failures.
- Adjusted dependency injection to reflect changes in media source management, removing old source registrations.
- Introduced background proxy checks to ensure a more robust proxy pool management during collection processes.

These changes streamline the media collection process and improve the overall user experience by providing clearer error reporting and more flexible source management.
2026-08-15 14:20:06 +03:00

6.7 KiB
Raw Blame History

Прокси-пул

Читать перед правкой Core/Proxies/** и Infrastructure/Proxies/**.

Добавить источник

  1. Реализовать IProxySource (или IMutableProxySource, если список редактируемый).
  2. Зарегистрировать в AddAvParserProxies(). Порядок регистрации = порядок слияния; свой список идёт последним, чтобы пользовательский адрес перебивал фидовый.

Инварианты

  • ProxyPool переиспользует существующие ProxyEntry по Endpoint.Key — иначе перезагрузка списка стирала бы статистику, а публичные фиды переиздаются каждые несколько минут.
  • Доступность определяется карантином, а не Health. Health — «что видели в последний раз»; исключать всё когда-либо упавшее значит потерять прокси после первой осечки. Уже было багом, ловит A_failing_proxy_is_quarantined_and_comes_back_later.
  • LiveCount считает только Alive и не в карантине. На нём висит гейт сбора, поэтому «доступна» (окно истекло) и «живая» намеренно расходятся: гейт не должен открываться от одного лишь истечения окна.
  • Проба не трогает SuccessCount/FailureCount — они про реальные запросы, а свип по паре тысяч адресов перезаписал бы всё, на чём держится взвешенный выбор. Провал пробы даёт карантин через RecordProbe(..., quarantineOnFailure:).
  • Лиза без вердикта нейтральна: отменённая операция — не вина прокси, иначе каждый Cancel карантинил бы здоровые адреса.
  • Вердикт лизы — про транспорт, а не про ресурс. 404 и 429 — успех прокси; иначе пул карантинил бы рабочие адреса с частотой мёртвых ссылок, а на лимит отвечал бы сменой прокси, то есть обходом лимита.
  • Прогрев обрывается по достижении цели, а не проходит список до конца: WarmUpAsync линкует CTS и гасит остаток на MinimumLiveProxies. Порядок кандидатов — WarmUpOrder(), публичный ровно ради проверки без прогона проб.
  • Остаток дочищает TopUpAsync в фоне. Прогрев по построению оставляет тысячи адресов в Unknown — это читается как «проверка не запускалась», и, что хуже, сбор получает пул из десяти прокси вместо сотен рабочих. Фоновый проход запускает ProxyPoolLoader после прогрева, с четвертью ProbeConcurrency: пользовательский свип — это всплеск, за которым смотрят, а этот идёт минутами и, возможно, параллельно с закачкой.
  • TopUpAsync трогает только Unknown. Перепроверять мёртвых — это и есть свип; перепроверять живых значит посадить в карантин прокси, которой прямо сейчас пользуется прогон.
  • TopUpAsync не делает _strategy.Reset(), в отличие от свипа: сброс уронил бы липкий выбор посреди сбора, причём ради записей, которых в этом выборе и нет. Changed он поднимает раз в ChangeInterval проб — иначе страница молчит несколько минут.
  • Фоновый проход не идёт при ProxyHealthCheck.Lazy: «проверять в момент выдачи» — это ровно просьба не свипать.
  • SaveStateAsync сериализован семафором. Писателей теперь двое (фоновый проход по завершении и выход из приложения), а запись идёт через один и тот же временный файл с переименованием.
  • RestoreState не выставляет Health = Alive — «работала вчера» живёт в WasAliveOnLastRun и влияет только на порядок прогрева. Иначе пул отрапортует живыми тех, с кем не разговаривал: прогрев сочтёт цель достигнутой, а гейт сбора откроется по данным недельной давности. Ловит A_remembered_proxy_is_not_reported_live_until_it_answers_again.
  • RestoreState не восстанавливает карантин: окно — стенные часы, между запусками могли пройти сутки, и перенос сажал бы прокси за давно истёкшее.
  • Сохраняются только HasEverAnswered = SuccessCount > 0 || IsBelievedAlive («believed» — вердикт этой сессии, а без него прошлой). Прогрев обрывается рано, поэтому большинство запомненных заканчивают сессию непроверенными — строгое Health == Alive стёрло бы накопленный список за пару запусков.
  • Select и Next зарезервированы для CA1716 — метод стратегии называется Pick.

Статистика на «Обзоре»

DashboardViewModel держит сводку пула и обновляет её по событию IProxyPool.Changed с throttle 250 мс — событие приходит на каждый исход лизы и на каждую пробу. «Живых» на карточке — это LiveCount, то же число, что читает гейт сбора; RefreshProxyStats() публичен, чтобы тесты не ждали throttle.