TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 548 subscribers
Post #220 115
پیاده‌سازی الگوی Outbox 📬


در سیستم‌های توزیع‌شده، ما اغلب با چالش همگام‌سازی دیتابیس و سیستم‌های خارجی مواجه هستیم. تصور کنید سفارشی را در دیتابیس ذخیره کرده و سپس پیامی را به یک message broker منتشر می‌کنید. اگر هر یک از این عملیات‌ها شکست بخورد، سیستم شما در وضعیتی ناسازگار (inconsistent) قرار می‌گیرد.

الگوی Outbox این مشکل را با در نظر گرفتن انتشار پیام به عنوان بخشی از تراکنش دیتابیس شما حل می‌کند. به جای انتشار مستقیم پیام‌ها، ما آن‌ها را در یک جدول Outbox در دیتابیس خود ذخیره می‌کنیم و از عملیات اتمیک اطمینان حاصل می‌کنیم. سپس یک فرآیند جداگانه این پیام‌ها را به طور قابل اعتماد منتشر می‌کند.

در این مقاله، ما به پیاده‌سازی این الگو در NET.، از راه‌اندازی تا مقیاس‌پذیری، خواهیم پرداخت.

چرا به الگوی Outbox نیاز داریم؟ 🤔

الگوی transactional Outbox یک مشکل رایج را در سیستم‌های توزیع‌شده حل می‌کند. این مشکل زمانی رخ می‌دهد که شما باید دو کار را همزمان انجام دهید: ذخیره داده و ارتباط با یک کامپوننت خارجی.

برای مثال، یک میکروسرویس را تصور کنید که باید:

🔹️ یک سفارش جدید را در دیتابیس خود ذخیره کند.

🔹️ در مورد این سفارش جدید به سیستم‌های دیگر اطلاع دهد.

🔹️ اگر یکی از این مراحل شکست بخورد، سیستم شما می‌تواند در وضعیتی ناسازگار قرار گیرد.
// کد با مشکل سازگاری بالقوه
public async Task<OrderDto> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
// ...
await unitOfWork.CommitAsync(cancellationToken);

// تراکنش دیتابیس در این نقطه کامل شده است
// 💥 اگر برنامه اینجا کرش کند یا event bus در دسترس نباشد چه؟
await eventBus.Send(new OrderCreatedIntegrationEvent(order.Id));

return new OrderDto { Id = order.Id, Total = order.Total };
}


الگوی transactional Outbox به حل این مشکل کمک می‌کند. 📈 ما هم سفارش و هم پیام Outbox را در یک تراکنش دیتابیس واحد ذخیره می‌کنیم. این یک عملیات "همه یا هیچ" است.

سپس یک پردازشگر Outbox جداگانه، ارسال واقعی پیام را مدیریت می‌کند. ⚠️ نکته مهمی که باید در اینجا متوجه شوید این است که الگوی Outbox به ما تحویل حداقل-یک‌باره (at-least-once delivery) را می‌دهد. این یعنی ما باید مصرف‌کنندگان پیام خود را idempotent بسازیم.

پیاده‌سازی الگوی Outbox 💾

ابتدا، جدول Outbox خود را ایجاد می‌کنیم:
CREATE TABLE outbox_messages (
id UUID PRIMARY KEY,
type VARCHAR(255) NOT NULL,
content JSONB NOT NULL,
occurred_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
processed_on_utc TIMESTAMP WITH TIME ZONE NULL,
error TEXT NULL
);

و کلاس #C برای نمایش ورودی Outbox:
public sealed class OutboxMessage
{
public Guid Id { get; init; }
public string Type { get; init; }
public string Content { get; init; }
public DateTime OccurredOnUtc { get; init; }
public DateTime? ProcessedOnUtc { get; init; }
public string? Error { get; init; }
}


✨️یک رویکرد زیبا برای پیاده‌سازی این، استفاده از domain events برای نمایش نوتیفیکیشن‌ها است. قبل از تکمیل تراکنش، می‌توانید تمام رویدادها را برداشته و آن‌ها را به عنوان پیام‌های Outbox ذخیره کنید.
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
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 →