Tutorials

TTL CAPTCHA-токенов в Redis в собственном backend

Безопасный scope: Это руководство применимо только к собственным или явно авторизованным QA-, staging- и production-средам. Описаны сценарии диагностики, тестирования и наблюдаемости вашей собственной CAPTCHA-интеграции — не для сторонних сайтов и не для несанкционированных workflow.

TTL ключа в Redis всегда должен быть короче, чем время жизни токена у провайдера проверки. Выставите их равными — и получите класс багов, который почти невозможно воспроизвести локально: токен лежит в кеше, EXISTS возвращает 1, а проверка на стороне провайдера отвечает timeout-or-duplicate. Ниже — как выбрать запас, как собрать идемпотентный ключ, как не отправить пять одинаковых задач вместо одной и по каким метрикам видно, что TTL подобран неверно.

Кеш здесь нужен не ради экономии. У CaptchaAI тарификация по потокам, а не по решениям: в любом тарифе от BASIC ($15/мес, 5 потоков) до VIP-3 ($7,500/мес, 5000 потоков) число решений в месяц не ограничено. Redis решает другую задачу — согласовать состояние между узлами и убрать дубли задач.

Как выбрать запас по времени

Запас — это разница между TTL провайдера и TTL ключа. Он должен покрывать три вещи: сетевой путь от Redis до обработчика, время самой отправки формы и разброс часов между узлами. Для одного дата-центра хватает примерно 10 % от TTL; для распределённой установки — скажем, воркеры в европейском регионе, а приложение на хостинге в Казахстане — закладывайте 20–30 с.

Тип проверки TTL у провайдера TTL ключа Redis Запас
reCAPTCHA v2 120 с 110 с 10 с
reCAPTCHA v3 120 с 110 с 10 с
Cloudflare Turnstile 300 с 270 с 30 с
GeeTest v3 120 с 110 с 10 с

Значения во втором столбце — заявленный срок жизни токена у самого провайдера проверки, а не характеристика CaptchaAI. Если ваш обработчик регулярно стоит в очереди дольше запаса, уменьшайте TTL ключа, а не растягивайте его.

Запись с истечением: одна команда вместо двух

SETEX ставит значение и срок жизни одной операцией. Связка SET плюс отдельный EXPIRE создаёт окно, в котором ключ уже существует, а срока у него ещё нет: падение процесса ровно в этот момент оставляет вечный ключ в памяти.

import redis, time

r = redis.Redis()

def remember(idem: str, token: str, ttl: int) -> None:
    r.setex(f'captcha:{idem}', ttl, token)

def get(idem: str) -> str | None:
    v = r.get(f'captcha:{idem}')
    return v.decode() if v else None

Идемпотентный ключ idem собирайте из контекста запроса: sitekey, идентификатор сессии или заказа, тип проверки. Ничего пользовательского в нём быть не должно — один ключ на двух пользователей означает, что чужой токен уйдёт в чужую форму.

Дедупликация задач через SETNX

Типичная картина под нагрузкой: пять воркеров одновременно видят промах кеша и отправляют пять одинаковых задач. Потоки заняты, счёт не растёт (тариф не зависит от числа решений), но задержка увеличивается, а четыре токена сгорают невостребованными.

Лечится блокировкой. Перед отправкой задачи выполните SET lock:<idem> 1 NX EX 120. Тот воркер, который получил OK, отправляет задачу в CaptchaAI; остальные короткими интервалами ждут появления ключа с токеном и забирают готовый результат. TTL на самой блокировке обязателен: если воркер упадёт до DEL, ключ снимется сам через две минуты и очередь не встанет намертво.

Что писать в логи

Структурированные логи помогают сравнивать поведение 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_token_expired_in_use — число случаев, когда токен из кеша был отвергнут при проверке. Пока счётчик около нуля, запас подобран верно. Как только он растёт вместе с нагрузкой, дело не в провайдере, а в слишком длинном TTL ключа.

Если в логи попадают идентификаторы пользователей, держите в уме 152-ФЗ «О персональных данных» и его зарубежные аналоги: пишите только те поля, которые вы вправе обрабатывать. Сам токен в открытый лог не кладите — по сути это одноразовый пароль.

Память и вытеснение

Ключи без TTL — главная причина роста памяти под Redis. Проверяется быстро: redis-cli --scan --pattern 'captcha:*', затем точечный TTL по выборке; значение -1 означает вечный ключ. Для кеша токенов включите maxmemory-policy allkeys-lru — при нехватке памяти Redis вытеснит самые холодные записи вместо того, чтобы отвечать ошибкой на запись.

Диагностика частых симптомов

Симптом Вероятная причина Что сделать
Токен из кеша отвергнут при проверке TTL ключа почти равен TTL провайдера Увеличьте запас на 20–30 с
Низкая доля попаданий в кеш Идемпотентный ключ слишком детальный Уберите из ключа изменчивые поля
Растёт объём памяти Есть ключи без TTL Пишите через SETEX, включите allkeys-lru
Дубли задач в CaptchaAI Нет блокировки перед отправкой SET ... NX EX 120 на время решения
Очередь встала после падения воркера Блокировка без срока жизни Добавьте EX к ключу блокировки

QA-чек-лист перед выкатом

  • Запрос отправляется только на собственные или авторизованные endpoints.
  • Тестовые учётные записи, события и платежи помечены как фиктивные.
  • CAPTCHA-токен проверяется на собственном backend, а не доверяется клиенту.
  • Каждый ключ получает TTL в той же команде, что и значение.
  • Логи содержат task_id, тип проверки, время ожидания и pass/fail.
  • Скрипт возвращает корректный exit code, чтобы CI мог принять решение.

FAQ

Какой запас ставить, если воркеры в разных регионах?

Возьмите P99 задержки между узлом Redis и обработчиком, прибавьте время отправки формы и округлите вверх. На практике для распределённой установки это 20–30 с, для одного дата-центра — около 10 с.

Почему SETEX, а не SET плюс EXPIRE?

Две команды дают окно, в котором ключ уже есть, а срока жизни у него нет. Падение процесса ровно в этот момент оставляет ключ в памяти навсегда — именно так набираются «утечки» на десятки гигабайт.

Нужно ли шифровать токены в Redis?

Токен живёт минуты и одноразовый, поэтому шифрование значения обычно избыточно. Важнее закрыть доступ к инстансу на уровне сети и requirepass, а в логи и трассировки токен не писать.

Как понять, что кеш вообще окупается?

Сравните долю попаданий и captcha_token_expired_in_use за неделю. Если попаданий меньше трети, а просрочки заметны, проще решать задачу каждый раз напрямую и оставить Redis только под блокировки.

Влияет ли кеширование на стоимость тарифа?

Нет. CaptchaAI считает параллельные потоки, а не решения, поэтому кеш экономит время ожидания, а не деньги. Тариф подбирают по нужному числу одновременных задач.

Смежные руководства

Нужен рабочий TTL-слой уже сегодня? Получите API-ключ CaptchaAI.

Комментарии для этой статьи отключены.