Где хранить информацию о первом проходе при генерации временного СМС-кода?

«Где хранить информацию о первом проходе при генерации временного СМС-кода?» — вопрос из категории Архитектура, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Ключевое требование — состояние («уже генерировали код или нет») должно быть временным, быстрым и общим для всех экземпляров приложения (если используется несколько серверов).

Рекомендуемые подходы:

  1. Распределенный кэш (IDistributedCache / Redis): Наилучший выбор для продакшена.

    • Почему: Высокая скорость, встроенное время жизни (TTL), данные доступны всем нодам приложения.
    • Пример для .NET:
      // Генерация и сохранение кода с проверкой
      public async Task<string> GenerateOrGetCodeAsync(string userId)
      {
      var cacheKey = $"sms_attempt_{userId}";
      // Пытаемся получить существующий код
      var existingCode = await _distributedCache.GetStringAsync(cacheKey);
      if (existingCode != null)
      {
          return existingCode; // Код уже был сгенерирован ранее
      }
      // Первый проход — генерируем новый код
      var newCode = GenerateRandomCode();
      var options = new DistributedCacheEntryOptions
      {
          AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
      };
      await _distributedCache.SetStringAsync(cacheKey, newCode, options);
      return newCode;
      }
  2. In-memory кэш (IMemoryCache): Подходит для однопроцессных приложений.

    • Почему: Максимально быстро, но состояние не разделяется между серверами. При рестарте приложения данные теряются.
  3. База данных: Используется реже для этого сценария.

    • Почему: Добавляет лишнюю нагрузку на БД. Может быть оправдано, если требуется строгий аудит всех попыток генерации или долгое хранение.

Важно: В качестве ключа кэша используйте комбинацию, уникальную для пользователя и операции (например, userId + phoneNumber), чтобы избежать коллизий.