Храните счётчик попыток для события, повторяйте только Pending с задержкой не меньше пяти секунд и завершайте обработку после OK или исчерпания трёх попыток. Error в примере считается окончательным отказом.
Задача: Поступают события от пользователей, каждое нужно верифицировать во внешнем источнике, но он отвечает не сразу.
Храните счётчик попыток для события, повторяйте только Pending с задержкой не меньше пяти секунд и завершайте обработку после OK или исчерпания трёх попыток. Error в примере считается окончательным отказом.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Задача: Поступают события от пользователей, каждое нужно верифицировать во внешнем источнике, но он отвечает не сразу.
Необходимо реализовать VerificationService который:
- Принимает события от пользователя
- Пытается верифицировать каждое, обращаясь к внешнему сервису
- Если ответ PENDING, повторяет отправку данного события не раньше чем спустя 5 секунд
- Максимум 3 попытки, после идентификатор события выводится в stdout со статусом FAILED
- Успешно обработанные события выводятся в stdout со статусом VERIFIED
Шаблоны и заготовки внешних зависимостей уже реализованы:
- VerificationStatus
- Event
- VerificationResult
- IExternalSource
public enum VerificationStatus { OK, Pending, Error }
public record Event(string Id, string Payload);
public record VerificationResult(VerificationStatus Status, string? Message = null);
public interface IExternalSource { VerificationResult Verify(string eventId); }
public class VerificationService { private readonly IExternalSource _externalSource; private const int MaxAttempts = 3; private static readonly TimeSpan RetryDelay = TimeSpan.FromSeconds(5);
public VerificationService(IExternalSource externalSource)
{
_externalSource = externalSource;
}
// TODO: реализовать
}
Ответ
Храните счётчик попыток для события, повторяйте только Pending с задержкой не меньше пяти секунд и завершайте обработку после OK или исчерпания трёх попыток. Error в примере считается окончательным отказом.
Метод можно добавить в заданный VerificationService:
public async Task ProcessAsync(Event evt, CancellationToken ct = default)
{
if (evt == null) throw new ArgumentNullException(nameof(evt));
for (int attempt = 1; attempt <= MaxAttempts; attempt++)
{
ct.ThrowIfCancellationRequested();
VerificationResult result;
try
{
result = _externalSource.Verify(evt.Id);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
throw;
}
catch (Exception)
{
Console.WriteLine($"{evt.Id} FAILED");
return;
}
if (result.Status == VerificationStatus.OK)
{
Console.WriteLine($"{evt.Id} VERIFIED");
return;
}
if (result.Status != VerificationStatus.Pending || attempt == MaxAttempts)
break;
await Task.Delay(RetryDelay, ct);
}
Console.WriteLine($"{evt.Id} FAILED");
}
Нужны System, System.Threading и System.Threading.Tasks. Каждый входящий Event передаётся в ProcessAsync; вызывающая сторона ожидает Task и ограничивает число одновременных обработок. Между завершением Pending-ответа и следующим вызовом выдерживается пять секунд; после третьего ожидания уже нет.
Отмена прерывает обработку, а не печатает FAILED. Исходный Verify синхронный и может блокировать поток; Task.Delay не исправляет это. Для production предпочтителен async-контракт с таймаутом и долговечная очередь повторов. Политика повторов Error и исключений в условии не задана, здесь они терминальные.