Инженерный кейс
Парк изолированных агентов
Панель управляет десятками учётных записей на торговой площадке. Каждая живёт на своём сервере, со своим адресом и своим устойчивым набором признаков браузера.
- комбинаций признаков
- 7 200
- бюджет перезапусков
- 5 / 300 с
- сервер на запись
- 1
Панель и парк агентов: на каждую учётную запись — отдельный сервер со своим адресом, на нём работает агент, который держит соединение с площадкой и выполняет команды панели. Панель раздаёт задания, собирает состояние и показывает всё в одном окне.
Панель и агент живут на разных машинах — и протокол это признаёт
Описание протокола лежит двумя одинаковыми файлами — в панели и в агенте. Это не забытый дубль: компоненты разворачиваются на разных серверах и обновляются независимо, и общий пакет на двоих означал бы, что выкладка панели ломает агентов, до которых новый код ещё не доехал.
Поэтому в каждом сообщении авторизации едет номер версии протокола: стороны сразу понимают, совместимы ли они, вместо того чтобы выяснять это на первой непонятой команде.
Признаки выводятся из ключа записи, а не берутся случайно
Набор параметров браузера — строка агента, профиль подписи соединения, язык — выбирается детерминированно: хеш от ключа записи по модулю длины списка, для каждого параметра со своей солью. Один и тот же агент из раза в раз выглядит одинаково.
Очевидное решение — случайный набор при каждом запуске — выдало бы автоматизацию быстрее, чем его отсутствие: живой человек не меняет браузер и язык системы между заходами. В коде посчитан и запас: 30 × 20 × 12 ≈ 7 200 комбинаций, вероятность совпадения на двадцати записях около 2,7%.
Надзиратель перезапускает только то, что действительно упало
За фоновыми потоками агента следит собственный надзиратель. Его правило записано в коде вместе с причиной: перезапуск происходит только от пойманного исключения в самом потоке — и ни от чего другого.
До этого за живостью следил внешний сторож по косвенному признаку, и в один день он положил здоровых агентов, потому что признак оказался грубым. Бюджет перезапусков жёсткий — пять за триста секунд; исчерпался, значит поток останавливается насовсем и нужен разбор, а не бесконечная карусель.
Отдельно и намеренно не надзираются два цикла: слушатель площадки и переподключение к панели. У обоих своя логика восстановления, и двойной надзор гонялся бы с ней наперегонки.
Агент сам понимает, что его больше нет
Если панель двадцать раз подряд отвечает «такого токена не знаю» — а с нарастающей паузой это 15–25 минут, — агент считает, что запись удалили в базе, пока до сервера не доехало обновление. Он затирает свои доступы, помечает себя выведенным и выходит.
Без этого удалённая из панели запись продолжала бы стучаться и работать со своими доступами на сервере, про который все забыли.
Первая пауза короткая — из-за гонки с базой панели
Свежеразвёрнутый агент успевает попросить авторизацию раньше, чем панель дозапишет его в базу. Раньше повтор шёл через тридцать секунд, и старт превращался в минуты простоя на ровном месте. Теперь пауза начинается с трёх секунд и удваивается: гонка разрешается за один-два повтора, а редкая настоящая ошибка всё равно доходит до длинных пауз.
Python · asyncio · WebSocket · SQLite (WAL) · systemd · Caddy