Главная причина, по которой QA-сюита на Puppeteer с CAPTCHA-проверками начинает тормозить по мере роста числа сценариев, — не решение CAPTCHA само по себе, а то, как вокруг него организован браузер. Если каждый сценарий поднимает новый инстанс Chromium, а токен CaptchaAI не переиспользуется между попытками внутри одного прогона, CI растягивается на десятки минут вместо нескольких. Ниже — паттерны, которые снимают эту нагрузку: один браузер на множество контекстов, параллелизм с явным лимитом, ретраи с задержкой и кеш токена на уровне сценария.
Область применения: паттерны ниже предназначены для собственных или явно авторизованных QA-, staging- и production-сред. Здесь нет обхода CAPTCHA на чужих сайтах — только диагностика, тестирование и наблюдаемость собственной интеграции CaptchaAI.
Один браузер на все Puppeteer-контексты
Поднимать новый браузер под каждый сценарий — самый частый источник медленных прогонов. browser.createIncognitoBrowserContext() даёт изолированный контекст (свои куки, свой localStorage) внутри одного и того же процесса Chromium, поэтому запуск браузера происходит один раз за весь прогон:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: 'new' });
async function withContext(fn) {
const ctx = await browser.createIncognitoBrowserContext();
const page = await ctx.newPage();
try { return await fn(page); }
finally { await ctx.close(); }
}
finally { await ctx.close(); } — не опция, а обязательное условие: без явного закрытия контексты копятся в памяти, и через 30–40 сценариев CI-раннер начинает падать по OOM.
Лимит параллелизма для CaptchaAI-запросов
Сценарии стоит параллелить с явным лимитом, а не «сколько потянет раннер»: неограниченный Promise.all по всем сценариям сразу упирается либо в память браузера, либо в очередь CaptchaAI.
import pLimit from 'p-limit';
const limit = pLimit(4);
await Promise.all(scenarios.map(s => limit(() => withContext(p => runScenario(p, s)))));
Если каждый параллельный контекст держит в моменте одну задачу CaptchaAI, для pLimit(4) из примера выше с запасом хватает плана STANDARD ($30/мес, 15 потоков). Для nightly-сюиты на 20+ параллельных контекстов логичнее сразу смотреть на ADVANCE ($90/мес, 50 потоков) — нужное число потоков считается напрямую от максимального числа одновременных сценариев.
Ретраи с экспоненциальной задержкой
При достаточном объёме прогонов сетевые сбои и временные ошибки CaptchaAI — норма, а не исключение. Один ретрай с фиксированной паузой почти всегда недостаточен под нагрузкой:
async function withRetry(fn, attempts = 3) {
let last;
for (let i = 0; i < attempts; i++) {
try { return await fn(); }
catch (err) { last = err; await new Promise(r => setTimeout(r, 1000 * (i + 1))); }
}
throw last;
}
Экспоненциальная задержка (1000 * (i + 1), то есть 1 с, 2 с, 3 с) не долбит API одинаковыми интервалами и даёт временному сбою шанс устраниться самому, прежде чем сценарий будет считаться упавшим.
Кеш CAPTCHA-токена на уровне сценария
Кешируйте токен внутри одного сценария, но не между разными сценариями или контекстами: токен привязан к конкретной странице и её sitekey, поэтому переиспользование между несвязанными прогонами приведёт не к экономии, а к ошибкам верификации на бэкенде.
Реально снижает нагрузку на CaptchaAI другое — внутренние ретраи одного и того же сценария. Если шаг формы падает по сети уже после того, как CAPTCHA решена, повторно дёргать CaptchaAI не нужно: токен ещё жив в рамках текущего прогона. Как только сценарий завершился — успешно или с ошибкой, — кеш сбрасывается вместе с контекстом.
Логи и наблюдаемость QA-сюиты
Структурированные логи помогают сравнивать поведение CAPTCHA между релизами и быстро находить регрессии в собственных формах:
import json, time, logging
log = logging.getLogger('captcha-qa')
def record(event: str, **fields) -> None:
payload = {'ts': time.time(), 'event': event, **fields}
log.info(json.dumps(payload, ensure_ascii=False))
Минимальный набор полей для каждой попытки: slug, captcha_type, task_id, wait_seconds, verify_status, env. Этого достаточно, чтобы построить дашборд медианы, P90 и P99 по типу CAPTCHA и по среде — и быстро увидеть, какой релиз замедлил решение Cloudflare Turnstile, а какой — reCAPTCHA v2.
Если сценарии логируют тестовые email или платёжные данные, помечайте их как фиктивные заранее — это дешевле, чем разбирать постфактум, соответствуют ли логи staging-среды требованиям 152-ФЗ «О персональных данных» или GDPR.
Типичные проблемы и их решение
| Симптом | Что сделать |
|---|---|
| Утечка памяти | Закрывайте контексты в finally |
| Параллельные тесты влияют друг на друга | Используйте incognito |
| Ретраи бесконечны | Ограничьте attempts |
| Токены тратятся слишком быстро | Кешируйте токен внутри сценария |
| CI-джоба падает по общему таймауту | Считайте таймаут на весь прогон, а не на один сценарий, и закладывайте время под ретраи |
| Сложно сравнить P90 между релизами | Фиксируйте один и тот же набор сценариев для каждого сравнения |
QA-чек-лист перед мержем
- Запрос отправляется только на собственные или авторизованные endpoints.
- Тестовые учётные записи, события и платежи помечены как фиктивные.
- CAPTCHA-токен проверяется на собственном backend, а не доверяется клиенту.
- Логи содержат
task_id, тип CAPTCHA, время ожидания и pass/fail. - Лимит параллелизма (
pLimit) и общий timeout джобы заданы явно, а не оставлены на усмотрение CI-раннера. - Скрипт возвращает корректный exit code, чтобы CI мог принять решение.
Частые вопросы
Можно ли использовать эти паттерны на сторонних сайтах?
Нет. Все сценарии в этой статье рассчитаны только на собственные или явно авторизованные среды. Для чужих ресурсов сначала нужно письменное разрешение владельца.
Что делать, если CaptchaAI вернул ошибку?
Залогируйте task_id, тип CAPTCHA и текст ошибки, повторите запрос с экспоненциальной задержкой и фиксируйте долю ошибок в дашборде. Если доля ошибок растёт от прогона к прогону, сначала проверьте sitekey и саму страницу, а не код ретраев.
Сколько потоков CaptchaAI нужно под параллельный QA-прогон?
Отталкивайтесь от значения pLimit: одновременных задач CaptchaAI в моменте примерно столько же, сколько параллельных контекстов Puppeteer. Для 4–5 контекстов достаточно STANDARD ($30/мес, 15 потоков); для крупных nightly-сюит — ADVANCE ($90/мес, 50 потоков).
Как безопасно кешировать токен, не ловя ложные срабатывания?
Держите кеш в рамках одного сценария и одного контекста и сбрасывайте его вместе с контекстом в finally. Токен, переиспользованный в другом сценарии или на другой странице, не пройдёт проверку на бэкенде — это не оптимизация, а источник ложных failed-тестов.
Как сравнивать результаты между релизами?
Сохраняйте логи в одном формате и стройте отчёт по медиане, P90 и P99 на одинаковом наборе сценариев. Сравнивайте только сопоставимые выборки в собственной среде — иначе разница будет объясняться разным набором сценариев, а не самим релизом.
Безопасные связанные руководства
- Быстрый старт CaptchaAI
- QA-тестирование CAPTCHA в авторизованных средах
- Тестирование CAPTCHA API на собственных формах
- Отладка: браузерный тест падает, API проходит
- reCAPTCHA v2 через API
- Cloudflare Turnstile через API
- GeeTest v3 через API
Хотите ускорить собственную QA-сюиту на Puppeteer? Подключите CaptchaAI и настройте пул потоков под параллельные прогоны.