TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2993 2.45K
День 2491. #ЗаметкиНаПолях
Паттерн Идемпотентный Потребитель. Начало

Распределенные системы по своей природе ненадёжны. Одна из ключевых проблем — гарантировать, что сообщения обрабатываются ровно один раз. Теоретически это невозможно гарантировать в большинстве систем. Если вы проектируете систему, предполагая, что каждое сообщение будет обработано ровно один раз, вы подвергаете себя риску неявного повреждения данных. Но мы можем спроектировать систему так, чтобы побочные эффекты применялись ровно один раз, используя паттерн «Идемпотентный потребитель».

Что может пойти не так при публикации
Предположим, сервис публикует событие при создании новой заметки:
await publisher.PublishAsync(
new NoteCreated(note.Id, note.Title, note.Content));

Конкретная реализация издателя или брокера сообщений не важна.

Теперь представьте:
- Издатель отправляет сообщение брокеру.
- Брокер сохраняет его и отправляет ACK.
- Сбой в сети: ACK не доходит до производителя.
- Производитель по тайм-ауту повторяет попытку публикации.
- Теперь у брокера два события NoteCreated.
С точки зрения производителя, он действовал правильно. Но потребитель получил два события о создании одной и той же заметки.

И это только один из путей возникновения сбоя. Вы также можете получить дубликаты из-за:
- Повторных доставок брокером.
- Сбоев потребителя + повторных попыток.
Т.е. даже если вы всё сделали «правильно» на издателе, потребителю всё равно придётся защищаться.

Идемпотентность на стороне издателя (управляет брокер)
Многие брокеры сообщений поддерживают идемпотентную публикацию посредством дедупликации сообщений, если вы укажете уникальный идентификатор сообщения. Например, Azure Service Bus может обнаруживать дубликаты и игнорировать повторные публикации сообщений с тем же идентификатором в течение заданного периода. Amazon SQS и другие брокеры также предлагают аналогичные гарантии.

Не нужно заново изобретать эту логику в вашем приложении. Ключ к успеху — назначить каждому сообщению стабильный идентификатор, уникально отражающий отправляемое логическое событие. Например, при публикации события NoteCreated:
var message = new NoteCreated(
note.Id, note.Title, note.Content)
{
MessageId = Guid.NewGuid() // либо note.Id
};

await publisher.PublishAsync(message);

Если происходит сбой сети после отправки сообщения, приложение может повторить попытку. Но когда брокер обнаруживает тот же MessageId, он понимает, что это дубликат, и безопасно отбрасывает его. Вы получаете дедупликацию без каких-либо специальных таблиц отслеживания или дополнительного состояния в вашем сервисе.

Эта идемпотентность на уровне брокера решает широкий класс проблем на стороне производителя: повторные попытки сети, временные сбои и дублирующиеся публикации.

Она не обрабатывает повторные попытки потребителя, которые происходят при повторной доставке сообщений или сбое вашего сервиса во время обработки.

С этим поможет шаблон «Идемпотентный потребитель».

Продолжение следует…

Источник:
https://www.milanjovanovic.tech/blog/the-idempotent-consumer-pattern-in-dotnet-and-why-you-need-it
  • 👍 12
More from @netdeveloperdiary
  1. Sep 30, 2026Post #3356
  2. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  3. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  4. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  5. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  6. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →