فروشگاه پس از ثبت سفارش باید رسید بسازد و موجودی انبار را بهروز کند. تیم میخواهد سرویس سفارش پیام را یک بار منتشر کند و دو مصرفکننده مستقل کار خود را انجام دهند. اما درست بعد از ثبت موجودی، فرایند انبار پیش از پاسخ به سامانه پیامرسان متوقف میشود. پیام دوباره میرسد و اگر برنامه بدون بررسی همان تغییر را تکرار کند، موجودی دو بار کم خواهد شد. این سناریو قرارداد pub/sub در Dapr را روشن میکند. تحویل یک رویداد، تکمیل کار تجاری و ثبت تأیید سه لحظه جداگانهاند و طراحی برنامه باید فاصله میان آنها را مدیریت کند.
موضوع، مؤلفه و برنامه سه نام جدا دارند
در Dapr، برنامه میتواند از طریق API انتشار و اشتراک با یک مؤلفه pub/sub کار کند. تعریف component مشخص میکند کدام پیادهسازی پیامرسان در پشت این نام قرار دارد و چگونه باید به آن وصل شد. topic نام جریان رویدادها در آن مؤلفه است. app ID نیز هویت منطقی یک برنامه Dapr را بیان میکند. در مثال فروشگاه، نام مؤلفه میتواند «پیامرسان داخلی»، نام موضوع «سفارشهای ثبتشده» و شناسه برنامه مصرفکننده «انبار» باشد. این نامها نقشهای متفاوت دارند. تغییر نام مؤلفه در یک محیط ممکن است برنامه را به پیامرسان دیگری هدایت کند، حتی اگر نام topic ثابت مانده باشد.
انتزاع API به برنامه اجازه میدهد بدون قراردادن کد خاص هر کارگزار در تمام مسیرهای تجاری پیام منتشر کند. با این حال ویژگیهای عملیاتی کارگزار همچنان اهمیت دارند. نگهداری پیام، ظرفیت، رفتار ترتیب، محدودیت اندازه و تنظیمات گروه مصرفکنندگان به مؤلفه و سامانه پشت آن وابستهاند. قبل از تعویض پیادهسازی، قرارداد مورد نیاز برنامه را فهرست کنید و با امکانات مؤلفه جدید بسنجید. موفقیت یک نمونه انتشار و دریافت کوچک به تنهایی نشان نمیدهد رفتار در زمان خرابی، بار سنگین یا توقف طولانی مصرفکننده یکسان خواهد بود. آزمایش باید همان فاصلهها و خطاهایی را شامل شود که کار واقعی فروشگاه تجربه میکند.
ناشر رویداد را از طریق sidecar میفرستد
سرویس سفارش پس از تصمیم به انتشار، نام مؤلفه و topic را در درخواست خود مشخص میکند. sidecar محلی درخواست را دریافت میکند و از طریق مؤلفه به کارگزار مربوط میفرستد. پاسخ موفق این مسیر به معنی پایان کار سرویس انبار یا رسید نیست. اگر کاربر باید بداند سفارش واقعاً برای ارسال آماده شده، آن وضعیت باید از نتیجه فرایند تجاری استخراج شود. نمایش عبارت «رسید صادر شد» فقط بر پایه موفقیت انتشار میتواند کاربر را گمراه کند، زیرا مصرفکننده شاید هنوز در انتظار پیام باشد یا به دلیل یک وابستگی خراب نتواند آن را پردازش کند.
در مسیر عادی Dapr میتواند داده منتشرشده را در پوشش CloudEvents قرار دهد. این پوشش اطلاعاتی مانند شناسه و نوع رویداد را برای تبادل ساختیافته فراهم میکند. ولی قرارداد داده کسبوکار همچنان باید طراحی شود. شماره سفارش، نسخه ساختار پیام و شناسه یکتای عملیات را مشخص کنید. شناسه انتشار و شماره سفارش ممکن است برای دو هدف متفاوت به کار روند. یک سفارش میتواند رویداد ثبت و رویداد لغو جدا داشته باشد، در حالی که تکرار همان رویداد ثبت باید به عنوان تکرار تشخیص داده شود. استفاده صرف از شماره سفارش برای حذف همه تکرارها ممکن است لغو معتبر بعدی را نیز اشتباهاً کنار بگذارد.
مشترک چگونه پیام را دریافت میکند؟
مشترک باید topic مورد نظر، نام مؤلفه و روش تحویل به برنامه را اعلام کند. Dapr روشهای اشتراک متفاوتی دارد که از جمله آنها تعریف declarative و اعلام برنامهای اشتراک است. در مدل درخواست به handler، sidecar مشترک پیام را از مؤلفه میگیرد و آن را به مسیر تعریفشده در برنامه میرساند. اینجا لازم است تفاوت «اشتراک موفق» و «آمادگی handler» دیده شود. ممکن است تعریف اشتراک درست باشد ولی مسیر برنامه اشتباه، endpoint ناآماده یا ساختار بدنه ناسازگار باشد. مشاهده جریان از کارگزار تا پاسخ برنامه، محل خطا را دقیقتر از نگاه کردن تنها به صف مشخص میکند.
برای آزمایش قرارداد، یک رویداد با شناسه قابل ردیابی بسازید. ثبت ناشر، پذیرش توسط کارگزار و دریافت در هر مشترک را با همان شناسه مرتبط کنید. اگر انبار پیام را گرفته اما رسید نگرفته، وضعیت اشتراک و گروه مصرف سرویس رسید را بررسی کنید. اگر هیچ کدام دریافت نکردهاند، نام topic، نام مؤلفه و مجوز ناشر نقاط مشترک بررسی هستند. اگر هر دو پیام را دریافت کردهاند ولی نتیجه تجاری ناقص است، وضعیت داخل برنامهها اولویت دارد. این روش دامنه مسئله را محدود میکند و از تغییر تنظیمات کل پیامرسان برای خطای یک handler جلوگیری میکند.
تحویل حداقل یک بار و اثر تکراری
Dapr برای pub/sub قرارداد تحویل حداقل یک بار را توصیف میکند. این قرارداد به برنامه میگوید یک پیام ممکن است بیش از یک بار برسد و مصرفکننده باید برای این حالت آماده باشد. فرض کنید handler انبار تراکنش کاهش موجودی را ثبت میکند و درست پیش از ارسال پاسخ از کار میافتد. در نگاه برنامه، تغییر ثبت شده است. در نگاه مسیر تحویل، تأیید موفق دریافت نشده است. تلاش مجدد میتواند همان رویداد را دوباره به handler برساند. خاموش کردن تکرار برای پنهان کردن مسئله ممکن است رویدادهایی را که واقعاً پردازش نشدهاند از دسترس خارج کند.
یک الگوی عملی، ثبت شناسه رویداد همراه با اثر تجاری در یک تراکنش مناسب است. handler پیش از اعمال دوباره تغییر بررسی میکند آیا همان رویداد برای همین نوع عملیات ثبت شده است. اگر ثبت موجود باشد، میتواند نتیجه سازگار برگرداند. اگر ثبت شناسه و تغییر موجودی در دو عملیات مستقل باشند، خرابی میان آنها هنوز پنجره خطا باقی میگذارد. برای اثر بیرونی مانند ارسال ایمیل نیز تراکنش پایگاه داده به تنهایی کافی نیست. برنامه باید از شناسه تکرارناپذیر سرویس بیرونی یا گردش کار قابل بازیابی استفاده کند. نوع اثر تعیین میکند مدیریت تکرار به چه طراحیای نیاز دارد.
پاسخ مصرفکننده تصمیم تحویل را شکل میدهد
در مدل تحویل به endpoint، پاسخ موفق برنامه علامتی است که پردازش از دید قرارداد تحویل کامل شده است. API همچنین امکان بیان نتیجههایی مانند RETRY یا DROP را میدهد. RETRY زمانی معنا دارد که خطا موقت است یا فرایند در تلاش بعدی امکان موفقیت دارد. DROP تصمیمی برای کنار گذاشتن پیام است و باید تنها بر اساس سیاست روشن و با ثبت دلیل انجام شود. اگر برنامه بلافاصله موفقیت اعلام کند و سپس کار سنگین را در حافظه محلی انجام دهد، از دست رفتن همان فرایند میتواند کار را پس از تأیید پیام ناپدید کند. نقطه تأیید باید با ثبت پایدار مسئولیت کار هماهنگ باشد.
خطای ناشی از قطع موقت پایگاه داده با خطای پیام دارای ساختار ناشناخته فرق دارد. تکرار سریع پیام خراب بدون تغییر چیزی، بار کارگزار و مشترک را افزایش میدهد. برای چنین حالتهایی سیاست تلاش مجدد، موضوع پیامهای ناموفق و فرایند رسیدگی انسانی یا خودکار کاربرد دارند. مقصد خطا نباید به انباری تبدیل شود که هیچ تیمی آن را نمیبیند. مالک بررسی، مدت نگهداری، روش اصلاح و قواعد بازپخش باید معلوم باشند. بازپخش پس از اصلاح نیز باید همان شناسه تجاری را حفظ کند تا مصرفکننده بتواند اثر اجراهای قبلی را در نظر بگیرد.
چند replica به معنی چند دریافت مستقل نیست
چند نمونه از یک برنامه معمولاً برای تقسیم کار در یک گروه مصرف اجرا میشوند. در این الگو یک پیام میان نمونههای رقابتکننده همان گروه به یک نمونه سپرده میشود. در مقابل، دو برنامه منطقی مستقل مانند انبار و صدور رسید باید هر کدام مسیر اشتراک مناسب خود را داشته باشند تا هر دو از رویداد سفارش مطلع شوند. اگر آنها ناخواسته یک گروه مصرف مشترک داشته باشند، ممکن است کار میان آن دو تقسیم شود و هر کدام تنها بخشی از پیامها را ببینند. تنظیم دقیق به مؤلفه و پیکربندی وابسته است و باید با مستندات همان کارگزار بررسی شود.
افزایش replica میتواند توان مصرف را بیشتر کند، اما ترتیب مشاهده تغییرها را نیز تحت تأثیر قرار میدهد. اگر دو رویداد برای یک سفارش باید به ترتیب پردازش شوند، نیاز ترتیب را به صراحت در طراحی پیام، کلید پارتیشن و منطق برنامه لحاظ کنید. اتکا به ترتیب تصادفی یک آزمون کمبار خطرناک است. handler میتواند نسخه یا شماره توالی تجاری را مقایسه کند و در برابر رویداد قدیمی رفتار روشن داشته باشد. این موضوع برای لغو سفارشی که پیشتر ارسال شده مهم است. رسیدن دیرهنگام رویداد ثبت نباید وضعیت لغوشده را بدون بررسی قوانین سفارش دوباره فعال کند.
فاصله ثبت سفارش تا انتشار رویداد
اگر برنامه سفارش را در پایگاه داده ثبت و سپس جداگانه پیام منتشر کند، خرابی بین این دو مرحله ممکن است سفارش ثبتشده بدون رویداد باقی بگذارد. انجام انتشار قبل از ثبت نیز حالت معکوس ایجاد میکند. الگوی outbox برای کاهش این شکاف مطرح است و Dapr امکانات مرتبط را برای ترکیبهای پشتیبانیشده مستند میکند. پیش از انتخاب باید سازگاری state store و مؤلفه pub/sub، قرارداد تراکنش و رفتار بازیابی را بررسی کرد. استفاده از یک نام الگو به تنهایی اثبات نمیکند دو سامانه مستقل در همه وضعیتها دقیقاً یک بار اثر تجاری ایجاد میکنند.
برای تمرین نهایی، سه خطا را جدا ایجاد کنید. ناشر پس از ثبت سفارش و پیش از ارسال متوقف شود، مشترک پس از ثبت اثر و پیش از تأیید از کار بیفتد، و یک پیام با نسخه ساختار ناشناخته وارد شود. برای هر مورد زمان تشخیص، نتیجه تجاری و روش بازیابی را ثبت کنید. شمار پیامهای منتشرشده، تلاشهای مجدد، سن قدیمیترین پیام منتظر و تعداد رسیدهای واقعاً صادرشده چهار نمای متفاوت میدهند. با پیوند این شاخصها به شناسه رویداد، تیم میتواند تشخیص دهد مشتری منتظر تحویل پیام است یا منتظر کاری که پس از تحویل هنوز به پایان نرسیده است.
در نمونه سفارش، برای بازپخش دستی یک رسید ناموفق، شناسه سفارش، شناسه رویداد و نتیجه تلاش قبلی را در اختیار مسئول عملیات بگذارید. اگر ایمیل پیشتر ارسال شده و فقط ثبت نتیجه قطع شده است، ارسال بیدرنگ پیام تازه به مشتری میتواند دو رسید مشابه بسازد. ابتدا وضعیت ارائهدهنده ایمیل را با شناسه قابل ردیابی بررسی کنید. اگر ارسال انجام نشده، همان عملیات را با شناسه پیشین ادامه دهید و نتیجه را کنار رویداد اصلی ثبت کنید. این روش به تیم پشتیبانی اجازه میدهد میان «پیام دوباره تحویل شد» و «رسید دوباره برای مشتری ارسال شد» تفاوت دقیقی بگذارد.