Skip to content

RateLimitMiddleware: pluggable storage (Redis/Memcached) - #487

Open
Ibochkarev wants to merge 3 commits into
betafrom
feat/issue-349-rate-limit-store
Open

RateLimitMiddleware: pluggable storage (Redis/Memcached)#487
Ibochkarev wants to merge 3 commits into
betafrom
feat/issue-349-rate-limit-store

Conversation

@Ibochkarev

Copy link
Copy Markdown
Member

Описание

RateLimitMiddleware больше не пишет счётчики напрямую в sys_get_temp_dir(). Логика вынесена в RateLimitStoreInterface; по умолчанию используется file-драйвер (поведение single-node сохранено). Для multi-node можно включить Redis или Memcached через системные настройки или env — без обязательной composer-зависимости (нужны только PHP-расширения).

Тип изменений

  • Исправление бага (non-breaking change)
  • Новая функциональность (non-breaking change)
  • Breaking change
  • Рефакторинг
  • Документация

Связанные Issues

Closes #349

Как включить Redis (multi-node)

  1. Установить ext-redis на всех PHP-нодах.
  2. Задать ms3_rate_limit_store = redis или env MS3_RATE_LIMIT_STORE=redis.
  3. Указать подключение:
    • ms3_rate_limit_redis_dsn = redis://:password@127.0.0.1:6379/0, или
    • env MS3_RATE_LIMIT_REDIS_DSN, или
    • host/port/password/database через отдельные настройки.

При недоступном Redis/Memcached middleware автоматически откатывается на file store (warning в MODX log).

Как это было протестировано?

cd core/components/minishop3
vendor/bin/phpunit tests/Unit/Services/RateLimit/ tests/Unit/Middleware/RateLimitMiddlewareTest.php  # exit 0 (5 tests)
composer ci:php  # exit 0 (smoke 20 + phpunit 44 tests)
php -l src/Services/RateLimit/*.php src/Middleware/RateLimitMiddleware.php  # exit 0
  • Ручное тестирование
  • Автоматические тесты
  • Тестирование на разных версиях PHP/MODX

Конфигурация: PHP 8.4.17, branch feat/issue-349-rate-limit-store

Чеклист

  • File store — дефолт
  • Документация включения Redis/Memcached — lexicon ru/en + PR
  • HTTP 429 без регрессии (unit-тест middleware)
  • TODO в middleware удалён
  • CHANGELOG — по политике репозитория не обновлялся

Extract file-based counters into RateLimitStoreInterface with optional
Redis/Memcached backends via MODX settings or env, keeping file as default.

Closes #349
@Ibochkarev Ibochkarev added priority: low Низкий приоритет, когда будет время enhancement New feature or request tech-debt Maintainability / refactor / architecture debt labels Jul 29, 2026
@Ibochkarev
Ibochkarev requested a review from biz87 July 29, 2026 16:27
Count the current request atomically before comparing to maxAttempts,
and initialize Memcached counters with add() to avoid init races.
RedisRateLimitStore now uses a single bucket key with a TTL window and
an atomic Lua script (INCR + EXPIRE in one round-trip), removing the
TOCTOU between the counter and a separate reset key. RateLimitStoreFactory
routes shared-store fallbacks through a single fallbackToFile() helper.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority: low Низкий приоритет, когда будет время tech-debt Maintainability / refactor / architecture debt

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] RateLimitMiddleware: pluggable storage (Redis/Memcached)

1 participant