FutureForgeFutureForge

خدمات FutureForge

  • طراحی و ساخت محصولاز شناخت نیاز تا انتشار محصول، یک مسیر روشن پیش رو دارید.
  • توسعه فول‌استکوب‌اپلیکیشن، API و داده را هماهنگ و یکپارچه توسعه دهید.
  • ممیزی مهندسیپیش از هزینه‌ی بیشتر، از وضعیت واقعی محصول‌تان باخبر شوید.
  • مشاوره معماریپیش از یک تصمیم فنی پرهزینه، گزینه‌ها را درست بسنجید.
  • زیرساخت و استقرارمحصول را با خیال راحت منتشر کنید و پایدار نگه دارید.
  • هوش مصنوعی در محصولهوش مصنوعی را فقط جایی به کار می‌گیریم که مسئله‌ای را حل کند.
نمونه‌کارهایادداشت‌هاقیمت‌گذاریدرباره ما
شروع گفتگو
  1. خانه
  2. /یادداشت‌ها
  3. /یادداشت‌ها
FutureForge

استودیوی مهندسی محصول — طراحی، ساخت و استقرار نرم‌افزار.

خدمات

طراحی سایت با وردپرستوسعه اختصاصیمهندسی محصولزیرساخت و استقرارمشاوره معماریهوش مصنوعی در محصول

راهنمای انتخاب

یادداشت‌هاقیمت‌گذاریتخمین هزینه پروژهمقایسه روش‌هانمونه‌کارهادرباره ماتماس

ارتباط

hello@futureforge.ir

ایده‌ای برای ساخت دارید؟

نیازتان را مطرح کنید تا درباره مسیر توسعه و قدم بعدی صحبت کنیم.

شروع گفتگو

© 2026 FutureForge. همه حقوق محفوظ است.

حریم خصوصیشرایط استفاده
خانهنمونه‌کارشروعتماس
معماری نرم‌افزار

اتصال فروشگاه به شرکت حمل‌ونقل: طراحی API و مدیریت خطا

سا
سهیل ابراهیم‌پور
·۴ آبان ۱۴۰۵·7 دقیقه مطالعه
اتصال حمل‌ونقلAPI حملretryidempotencyفروشگاه اینترنتی
توسعه‌دهنده کنار نمودار اتصال فروشگاه به شرکت حمل‌ونقل

برای اتصال به API حمل‌ونقل، قرارداد داخلی، timeout و retry با backoff و jitter، idempotency در ساخت مرسوله و آشتی وضعیت را طراحی کنید.

برچسب حمل، کد رهگیری، «بسته تحویل شد»: ظاهراً سه فراخوانی ساده به API شرکت حمل‌ونقل. مشکل از جایی شروع می‌شود که درخواست ساخت برچسب timeout می‌خورد و نمی‌دانید برچسب ساخته شده یا نه؛ یا وضعیت «تحویل شد» دو بار می‌رسد؛ یا شرکت حمل وضعیت‌هایی دارد که در سفارش شما معادل ندارند. این مقاله یک طراحی مشخص برای اتصال فروشگاه به حمل‌ونقل می‌دهد: قرارداد داخلی، مدیریت خطا، retry امن و آشتی وضعیت.

مرزها را صریح بگوییم. ما API هیچ شرکت حمل‌ونقل ایرانی (مثل پست یا پیک‌های اینترنتی) را بررسی نکرده‌ایم، پس نام فیلد، کد خطا یا نحوهٔ رهگیری هیچ‌کدام را نقل نمی‌کنیم و فقط الگوی عمومی را می‌گوییم. الگوهای retry، backoff و idempotency از مستند Amazon Builders Library و Stripe آمده‌اند؛ آن‌ها دربارهٔ سرویس‌های ابری‌اند، اما اصل‌شان برای هر API راه دور برقرار است. بخش‌های «توصیهٔ نویسنده» مستقل از منبع‌اند. درباره قرارداد حمل، تعرفه یا الزامات حقوقی ارسال هم ادعایی نداریم.

قرارداد داخلی حمل‌ونقل

توصیهٔ نویسنده: کد سفارش نباید نام فیلدهای یک شرکت حمل را بشناسد. یک واسط داخلی کوچک بنویسید و هر شرکت را پشت آن بگذارید:

عملیاتورودیخروجی داخلیریسک اصلی
create_shipment(order)آدرس، وزن/ابعاد، شناسهٔ سفارششناسهٔ مرسوله + برچسب/کدتکرار ساخت (دو برچسب برای یک سفارش)
get_tracking(shipment)شناسهٔ مرسولهفهرست رویدادهای وضعیتتأخیر یا ترتیب ناهمگون
cancel_shipment(shipment)شناسهٔ مرسولهنتیجهٔ لغولغو بعد از تحویل به حامل
parse_webhook(request)درخواست ورودی (اگر شرکت دارد)رویدادهای وضعیت داخلیجعل و تکرار

وضعیت‌های شرکت حمل را به وضعیت‌های خودتان نگاشت کنید: مثلاً label_created، handed_over، in_transit، out_for_delivery، delivered، delivery_failed، returned. وضعیتی که نگاشت ندارد را دور نیندازید؛ آن را ذخیره کنید و هشدار بدهید تا بعداً نگاشت اضافه شود.

اتصال سفارش به حمل‌ونقل با retry و رهگیری
نمودار مفهومی.

timeout: هر فراخوانی راه دور سقف دارد

مستند AWS می‌گوید برای هر فراخوانی راه دور باید timeout گذاشت، هم برای برقراری اتصال و هم برای خود درخواست. دلیلش این است که کلاینتی که منتظر می‌ماند، منابعش (حافظه، رشته، اتصال) را نگه می‌دارد و اگر چندین درخواست همین‌طور بمانند، سرور منابعش را از دست می‌دهد. انتخاب عدد سخت است: timeout بلند کارایی‌اش را از دست می‌دهد و timeout کوتاه باعث می‌شود درخواست‌ها بی‌دلیل retry شوند و ترافیک و تأخیر بالا برود. Amazon برای فراخوانی‌های داخلی از تأخیر صدک‌های سرویس مقصد (مثلاً p99.9) شروع می‌کند؛ اما همین مستند می‌گوید این روش برای مسیرهای اینترنتی با تأخیر شبکهٔ زیاد جواب نمی‌دهد و باید بدترین تأخیر معقول شبکه را هم حساب کرد.

در عمل برای شما: از اندازه‌گیری شروع کنید. زمان پاسخ واقعی API حمل را چند روز ثبت کنید، آن‌گاه timeout را بالاتر از رفتار عادی و پایین‌تر از تحمل کاربر بگذارید. اینکه عدد دقیق چقدر باشد از این مقاله برنمی‌آید، چون به API و زیرساخت شما بستگی دارد.

retry با backoff و jitter

AWS توضیح می‌دهد retry شکست‌های گذرا و جزئی را پوشش می‌دهد، اما اگر سیستم مقصد به‌خاطر اضافه‌بار شکست می‌خورد، retry بار را بیشتر می‌کند. راه‌حل backoff است: فاصلهٔ بین retryها زیاد می‌شود. و چون ترافیک معمولاً انفجاری است (مثلاً یک cron که هر شب در یک ساعت اجرا می‌شود)، اگر همهٔ کلاینت‌ها هم‌زمان retry کنند باز مشکل برمی‌گردد؛ برای همین jitter، یعنی مقدار تصادفی تأخیر، اضافه می‌شود. قواعد پیشنهادی (توصیهٔ نویسنده، مبتنی بر این اصول):

  • retry فقط برای خطاهای گذرا (timeout، خطای شبکه، پاسخ‌های «بعداً امتحان کن») و نه برای خطاهای دائمی مثل «آدرس نامعتبر».
  • سقف تعداد retry و سقف زمان کل مشخص باشد؛ بعد از آن سفارش به صف بررسی دستی برود.
  • تأخیر بین retryها افزایشی و دارای jitter باشد.
  • کار ارسال از مسیر پاسخ به کاربر جدا باشد: مشتری نباید منتظر API حمل بماند. سفارش را ثبت کنید و ساخت مرسوله را در صف انجام دهید.

idempotency: برچسب دوم نساز

AWS تأکید می‌کند timeout یا خطا الزاماً به معنی نبودن اثر جانبی نیست. اگر درخواست «بساز» timeout خورد، ممکن است سمت شرکت حمل انجام شده باشد. اگر تکرار اثر ناخواسته است، توصیهٔ AWS طراحی API به‌صورت idempotent است. Stripe همین را با کلید idempotency نشان می‌دهد: درخواست پس از خطای اتصال امن تکرار می‌شود، پاسخ اولین درخواست برمی‌گردد و تغییر پارامترها خطا می‌دهد. برای حمل‌ونقل این‌طور عمل کنید:

  1. اگر API شرکت حمل کلید idempotency یا «شناسهٔ مرجع پذیرنده» دارد، شناسهٔ سفارش خودتان را آن‌جا بدهید. اینکه هر شرکت چنین امکانی دارد یا نه را از مستند خودش بخوانید؛ ما بررسی نکرده‌ایم.
  2. اگر ندارد، پیش از ساخت مرسوله، «تلاش ساخت» را با وضعیت creating در دیتابیس خود ثبت کنید. بعد از timeout، قبل از تلاش دوباره، با شناسهٔ سفارش در API حمل جست‌وجو کنید (اگر چنین جست‌وجویی دارد) تا برچسب دوم نسازید.
  3. برای هر مرسوله فقط یک رکورد فعال داشته باشید (قید یکتایی در دیتابیس).

وضعیت: webhook یا polling؟

اگر شرکت حمل webhook می‌فرستد، قواعد مستند Stripe بسیار آموزنده‌اند: رویدادها ممکن است تکراری برسند و ترتیب تضمین‌شده ندارند، پس شناسهٔ رویدادها را ثبت کنید و بر زمان رویداد برای ترتیب‌دهی اتکا نکنید؛ پیش از منطق سنگین سریع پاسخ 2xx بدهید و پردازش را در صف ناهمگام انجام دهید. اگر شرکت webhook ندارد، polling دوره‌ای برای مرسوله‌های فعال لازم است. توصیهٔ نویسنده برای polling: فاصلهٔ استعلام را بر اساس وضعیت تنظیم کنید (مرسولهٔ تازه‌تحویل‌شده‌به‌حامل کمتر از مرسولهٔ در حال تحویل به مشتری)، و مرسوله‌های تحویل‌شده را از چرخه خارج کنید تا هزینهٔ فراخوانی و محدودیت نرخ API زیاد نشود.

ورود یک رویداد جدید باید این قاعده را دنبال کند: وضعیت را فقط «جلو» ببرید. اگر رویداد in_transit بعد از delivered رسید، ثبتش کنید ولی وضعیت سفارش را عقب نبرید. جدول گذارهای مجاز برای مرسوله بنویسید، همان‌طور که برای سفارش.

آشتی وضعیت سفارش و مرسوله

وضعیت سفارش را از وضعیت مرسوله جدا نگه دارید و با قاعدهٔ مشخص به‌هم وصل کنید: «وقتی مرسوله delivered شد، سفارش delivered می‌شود». اما انتظار داشته باشید گاهی ناهماهنگی پیش بیاید؛ مثلاً سفارش در انبار «ارسال‌شده» است ولی شرکت حمل می‌گوید «برچسب ساخته شده و تحویل نگرفته‌ام». یک کار دوره‌ای بنویسید که این موارد را پیدا کند:

  • سفارش‌هایی که بیش از آستانه‌ای (که خودتان تعیین می‌کنید) در label_created مانده‌اند.
  • مرسوله‌هایی که وضعیت‌شان مدتی تغییر نکرده است.
  • مرسوله‌های بدون سفارش یا سفارش‌های بدون مرسوله.

این موارد را به هشدار و صف بررسی ببرید. برای مبانی هشدار، Monitoring چیست؟ را ببینید. شاخص‌های مفید: تعداد retry برای هر مرسوله، درصد خطای هر شرکت، و تعداد وضعیت‌های بدون نگاشت.

دسته‌بندی خطاها و رفتار پیشنهادی

نوع خطامثالرفتار
گذراtimeout، قطع شبکه، پاسخ «مشغول»retry با backoff و jitter، با سقف
دائمی دادهٔ ورودیآدرس یا کد پستی نامعتبربدون retry؛ سفارش به صف «اصلاح آدرس»
دائمی پیکربندیکلید نامعتبر، حساب غیرفعالهشدار فوری؛ توقف صف تا رفع
نامشخصtimeout روی ساختابتدا جست‌وجو برای مرسولهٔ موجود، بعد تصمیم

چک‌لیست پیاده‌سازی

  1. واسط داخلی حمل با نگاشت وضعیت‌ها وجود دارد.
  2. همهٔ فراخوانی‌ها timeout (اتصال و درخواست) دارند و مقدار آن‌ها از اندازه‌گیری آمده است.
  3. retry فقط برای خطای گذرا، با backoff، jitter و سقف.
  4. ساخت مرسوله idempotent است یا پیش از تلاش دوباره جست‌وجو می‌شود.
  5. رویدادهای تکراری و نامرتب بی‌اثرند.
  6. وضعیت فقط به جلو می‌رود.
  7. کار دوره‌ای آشتی و هشدار برقرار است.
  8. شرایط ارسال، تعرفه و الزامات حقوقی از قرارداد و منبع رسمی بررسی شده‌اند، نه از این مقاله.

برای تصمیم‌های معماری بزرگ‌تر، انتخاب معماری اپلیکیشن وب را ببینید.

منابع و مراجع

  • Timeouts, retries, and backoff with jitter — Amazon Builders' Library (AWS)، 2019-12-05.
  • Idempotent requests (Stripe API) — Stripe.
  • Receive Stripe events in your webhook endpoint — Stripe.

نویسنده

سا

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

یادداشت‌های مرتبط

یادداشت‌های مرتبط

دسته‌بندی‌ها

خدمات مرتبط

از یادداشت تا پروژه

اگر با مسئله‌ای شبیه این روبه‌رو هستید، درباره‌ی شرایط پروژه‌تان با هم صحبت کنیم.

برای انتخاب مسیر فنی پروژه‌تان کمک می‌خواهید؟

از مسئله و محدودیت‌هایتان بگویید؛ اگر بتوانیم همراهی‌تان کنیم، برای گفت‌وگو هماهنگ می‌کنیم.

سهیل ابراهیم‌پور
یادداشت‌ها
اتصال موجودی انبار به فروشگاه: منبع حقیقت، همزمانی و idempotency
اتصال درگاه پرداخت اینترنتی به‌صورت قابل‌تعویض
مدیریت سفارش فروشگاه اینترنتی: ماشین حالت پرداخت، لغو و بازپرداخت
خواندن EXPLAIN ANALYZE در PostgreSQL
طراحی pagination API: offset، cursor و ترتیب پایدار

معماری نرم‌افزار

اتصال موجودی انبار به فروشگاه: منبع حقیقت، همزمانی و idempotency

۳ آبان ۱۴۰۵

معماری نرم‌افزار

اتصال درگاه پرداخت اینترنتی به‌صورت قابل‌تعویض

۳ آبان ۱۴۰۵

معماری نرم‌افزار

مدیریت سفارش فروشگاه اینترنتی: ماشین حالت پرداخت، لغو و بازپرداخت

۲ آبان ۱۴۰۵

معماری نرم‌افزار

خواندن EXPLAIN ANALYZE در PostgreSQL

۲ آبان ۱۴۰۵

معماری نرم‌افزار

طراحی pagination API: offset، cursor و ترتیب پایدار

۲ آبان ۱۴۰۵
همه یادداشت‌ها297
معماری نرم‌افزار25
واژه‌نامه37
عملیات و استقرار90
مهندسی محصول117
راهنمای وب28
طراحی و ساخت محصول
توسعه فول‌استک
ممیزی مهندسی
مشاوره معماری
زیرساخت و استقرار
شروع گفتگو
ابزارهای رایگان
شروع گفتگو