axe/internal/db/migrations/0009_rate_limits.sql

33 lines
2.1 KiB
MySQL
Raw Permalink Normal View History

2026-10-18 19:07:25 +00:00
-- 0009_rate_limits — счётчики брутфорс-лимитов в БД вместо памяти.
--
-- Раньше лимитер был in-memory (internal/ratelimit): перезапуск API
-- обнулял все счётчики, а при нескольких инстансах каждый считал своё.
-- Таблица решает оба: строка переживает рестарт и общая для всех
-- инстансов, подключённых к базе.
--
-- Семантика — то же фиксированное окно, что и раньше: строка с ключом
-- живёт window_start..window_start+window, внутри — счётчик попыток;
-- инкремент и сброс окна делаются одним upsert'ом (см. ratelimit.DBLimiter).
--
-- Ключ — «имя лимита|IP» (login|1.2.3.4): четыре эндпоинта с разными
-- потолками живут в одной таблице, IP не обязан быть глобальным ключом.
--
-- Чистка протухших строк — фоновым тикером в cmd/api (RunCleanup):
-- все окна — минутные, поэтому строки старше 10 минут бесполезны.
-- Без чистки таблица росла бы со скоростью уникальных IP.
--
-- Применённый файл не редактировать (checksum в schema_migrations).
CREATE TABLE rate_limits (
-- «имя лимита|IP»; primary key — и есть точка апсерта
key text PRIMARY KEY,
-- начало текущего окна; старше окна — счётчик начинается заново
window_start timestamptz NOT NULL DEFAULT now(),
-- попыток в текущем окне
count integer NOT NULL DEFAULT 0,
CHECK (count >= 0)
);
-- Чистка по времени: DELETE по window_start идёт по индексу.
CREATE INDEX rate_limits_window_start_idx ON rate_limits (window_start);