Перейти к основному содержимому

ADR-0042: Distributed Locking

Статус

Принято.

Контекст

В условиях multi-replica k8s deployment несколько pod-ов могут одновременно попытаться выполнить одну и ту же операцию: активировать бонус для игрока, запустить scheduled job, обработать payment callback. Оптимистичный concurrency через EF xmin достаточен для коротких DB write операций, но не защищает от race conditions при длинных операциях с external calls или при необходимости fail-fast без retry.

Решение

Использовать madelson/DistributedLock как единую библиотеку distributed locking с двумя backend-ами:

  • Redis — операционные locks (incentive claim, job deduplication, payment callback). Быстрый, TTL-based.
  • PostgreSQL advisory lock — migration locks. Надёжнее, survives Redis restart.

IPinLockProvider абстрагирует backend. Сервисы не зависят напрямую от DistributedLock.*.

DistributedJobRunner обеспечивает паттерн leader election для scheduled jobs: только один pod выполняет job.

Lock keys всегда включают entity type и entity id — для изоляции на уровне объекта, а не типа.

Последствия

  • Incentive claim race condition устранён — повторная активация одного бонуса невозможна.
  • Scheduled jobs выполняются ровно один раз при любом количестве replicas.
  • Distributed lock не заменяет DB transaction — оба используются совместно.
  • Операция при занятом lock возвращает Result.Fail с typed error, не retry (кроме migration lock).

Ссылки

Обратные ссылки

Автоссылки: где используется этот документ.