بلاگ

دو بار Publish دبانے سے اب ایک بار ہی publish ہوتا ہے

ایک ہی app کی تین publish درخواستیں 84 ملی سیکنڈ کے فرق سے ہمارے API تک پہنچیں، اور ہر ایک نے اس app کا مکمل deploy شروع کر دیا۔ وہ ایک دوسرے سے ایک ہی hosting پر دوڑ گئیں، اور نتیجتاً کئی releases ناکام ہوئے کیونکہ کوئی اور پہلے پہنچ چکا تھا۔ نظر آنے والی واحد علامت “release failed” کی ای میل تھی، جبکہ app خود ٹھیک چل پڑی۔ اب ایک publish جو کسی ایسی app کے لیے آئے جس کی دوسری publish چل رہی ہو، دوسرا build شروع نہیں کرتا۔ database فیصلہ کرتا ہے کہ کون سی درخواست جیتے گی، اور باقی کو سچ بتایا جاتا ہے: ایک publish پہلے سے چل رہی ہے۔

کیا ہوا

جب آپ Mythex پر کوئی app publish کرتے ہیں تو API اس app کے لیے ایک deployment ریکارڈ کرتا ہے اور ہمارے orchestrator سے کہتا ہے، یعنی وہ سروس جو builds چلاتی ہے، کہ اسے بنائے اور release کرے۔ publish Publish بٹن سے، کسی اور براؤزر tab سے، یا آپ کے کہنے پر ایجنٹ سے شروع ہو سکتا ہے۔ دو بار کلک، دو tabs، یا ایک ایجنٹ درخواست جو دو بار پہنچے، یہ سب ایک ہی app کے لیے تقریباً ایک ہی لمحے میں ایک سے زیادہ publish پیدا کر سکتے ہیں۔

اس صورت میں تین ایک 84 ملی سیکنڈ کے اندر پہنچے۔ ہر ایک نے مکمل deploy چلایا۔ hosting پلیٹ فارم پر اسی app کے releases ایک ہی سیکنڈ میں بنے، اور ان میں سے تین ناکام ہو گئے کیونکہ دوسرے پہلے سے چل رہے تھے۔ ایک بعد والا release اٹک گیا، اور اس کے بعد app کام کرتی رہی۔

یہی بات اسے پکڑنا مشکل بناتی تھی۔ صارف کو ایک کام کرتی app نظر آتی تھی۔ ناکامیاں صرف release کی ناکامی والی ای میلز میں آتی تھیں۔

کچھ کیوں نہیں روکتا تھا

publish کے کوڈ میں ایک قدم تھا جو اس پروجیکٹ کے چلتے deployments کو دیکھتا تھا۔ مگر وہ کرتا یہ تھا کہ شروع ہونے سے پہلے ہر چلتے deployment کو ناکام نشان زد کر دیتا: “ایک نئی publish نے اسے بدل دیا”۔ اس کا مقصد تھا کہ وہ builds صاف ہوں جو کسی crash ہونے والے process نے پیچھے چھوڑے ہوں۔

عملی طور پر، build کے دوران آنے والی دوسری publish پہلی کو مردہ قرار دے دیتی اور اپنا build شروع کر دیتی۔ دونوں ایک ہی app پر آخر تک چلتے رہتے۔ کوئی lock نہیں تھا؛ ایک ایسا قدم تھا جو فعال طور پر دوڑ کے لیے راستہ صاف کرتا تھا۔

ایک اور، عجیب علامت کسی app کی پہلی publish کے لیے تھی۔ جب deployment ریکارڈ ابھی دوبارہ استعمال کے لیے موجود نہ ہو تو دو بیک وقت پہلی publishes دونوں ایک ہی ریکارڈ داخل کرنے کی کوشش کرتیں۔ database میں app کے لنک کے نام (اس کا slug، جیسے your-app in your-app.mythex.ai) پر ایک unique index ہے، اس لیے دوسرا insert ناکام ہو جاتا۔ API اسے “یہ لنک نام لیا جا چکا ہے” میں بدل دیتا، اور صارف کو مشورہ دیتا کہ وہ ایک ایسی app کا نام بدلے جو اسی لمحے اسی نام سے کامیابی سے publish ہو رہی تھی۔

حل: دعویٰ ہی lock ہے

deployment ریکارڈ پر دعویٰ اب ایک ہی شرطی database update ہے: یہ قطار لو اور اسے building نشان زد کرو صرف اس صورت میں جب کوئی اور publish نہ کر رہا ہو۔ چونکہ یہ ایک ہی statement ہے، database ان درخواستوں کا فیصلہ کرتی ہے جو ایک ہی ملی سیکنڈ میں پہنچیں۔ ٹھیک ایک درخواست row بدلتی ہے۔ باقی دیکھتی ہیں کہ صفر rows بدلیں، رک جاتی ہیں، اور orchestrator تک کبھی نہیں پہنچتیں۔

lock کو اپنے مالک کے مرنے پر نکلنے کا راستہ بھی چاہیے۔ اگر API ایک publish کے بیچ میں دوبارہ شروع ہو جائے تو row ہمیشہ کے لیے “building” رہتی اور app ناقابلِ publish ہو جاتی۔ اس لیے وہ row جس کے مالک نے heartbeats بھیجنا بند کر دیا ہو، دوبارہ دعوے کے لیے کھل سکتی ہے: چلتی publish ہر 30 سیکنڈ پر row کو اپڈیٹ کرتی ہے، اور پانچ منٹ کی خاموشی کو مردہ شمار کیا جاتا ہے۔ یہ حد heartbeat سے آتی ہے، build کے وقت کے کسی اندازے سے نہیں۔ صارف کا اپنا Dockerfile بنانا جائز طور پر لمبا وقت لے سکتا ہے، اور ایک سست build جو اب بھی heartbeat دے رہا ہو اپنا دعویٰ برقرار رکھتا ہے۔

وہ قدم جو publish سے پہلے ہر چلتے deployment کو ناکام کرتا تھا اب نہیں چلتا۔ صرف وہ rows صاف ہوتی ہیں جو کسی مرے ہوئے process نے پیچھے چھوڑی ہوں۔

ہارنے والے کو سچ بتانا

جو درخواست ہارتی ہے اسے اب واضح جواب ملتا ہے: publish_in_progress، اس چلتے deployment کے ID کے ساتھ۔ publish شروع کر سکنے والی ہر جگہ اسے سنبھالتی ہے:

  • Workspace پہلے سے چلتے build کو فالو کرتا ہے، بجائے اس کے کہ اس کے اوپر ایک خرابی دکھائے۔
  • ایجنٹ کو بتایا جاتا ہے کہ اس app کی publish پہلے سے چل رہی ہے اور اس کا انتظار کرے، نہ کہ اسے بتایا جائے کہ کچھ ناکام ہوا، جو پہلے اسے Dockerfile “ٹھیک کرنے” اور دوبارہ کوشش کرنے پر بھیج سکتا تھا۔
  • پہلی publish کا link name پر تصادم جانچا جاتا ہے: اگر نام رکھنے والی row اسی پروجیکٹ کی چلتی publish ہے تو جواب “پہلے سے publish ہو رہی ہے” ہے، نہ کہ “یہ نام لیا جا چکا ہے”۔ کسی اور پروجیکٹ کے ساتھ حقیقی تصادم پر اب بھی نام بدلنے کا پیغام آتا ہے۔

ہم نے کیسے جانچا

ہم نے ایک reproduction script لکھی جو ایک حقیقی database اور ایک stub orchestrator کے خلاف ایک ہی app کی تین publishes ایک ساتھ چلاتی ہے، اور گنتی کرتی ہے کہ orchestrator سے کتنے deploys مانگے گئے۔ یہ پہلی publish اور ایک live app کی republish دونوں کو کور کرتی ہے۔ fix سے پہلے یہ دو deploys گنتی تھی۔ بعد میں ایک۔

یہ script escape hatch کو بھی کور کرتی ہے: یہ app کی row کو دس منٹ کی بغیر heartbeat کے building نشان زد کرتی ہے، دوبارہ publish کرتی ہے، اور جانچتی ہے کہ نئی publish row کا دعویٰ کر کے چلتی ہے۔

unit tests lock کے دو کاموں کو پکڑتے ہیں: ایک ساتھ تین republishes میں سے ٹھیک ایک گزرتی ہے اور باقی دو کو بتایا جاتا ہے کہ publish چل رہی ہے؛ اور وہ build جس کا مالک مر گیا ہو دعویٰ کیا جا سکتا ہے۔ ایک اور ٹیسٹ جانچتا ہے کہ نئی کوشش پچھلی کوشش کا خرابی پیغام ساتھ نہیں لے جاتی۔

ہم نے کیا سیکھا

  • صفائی کا کوڈ چھپی ہوئی دوڑ ہو سکتا ہے۔ “جو چل رہا ہو اسے ناکام کرو، پھر شروع کرو” صفائی کی طرح لگتا ہے۔ دو callers کے ساتھ، یہ ہر ایک کا دوسرے کو منسوخ کرنا ہے۔
  • database کو فیصلہ کرنے دیں۔ پڑھو، پھر لکھو، کے درمیان ایک خلا ہے جہاں دوسری درخواست داخل ہو سکتی ہے۔ ایک ہی شرطی update یہ خلا نہیں چھوڑتا۔
  • ہر lock کی میعاد زندگی سے جڑی ہونی چاہیے۔ اس کے بغیر ایک crash اٹکی ہوئی app بن جاتا ہے۔
  • خرابی کے پیغام ہدایات ہوتے ہیں۔ “یہ نام لیا جا چکا ہے” نے لوگوں کو غلط کام کی طرف بھیجا۔ درست پیغام سادہ تھا اور سچا تھا۔

docs میں publishing کے بارے میں مزید: publish کیسے کریں۔ اور ایک متعلقہ fix: آپ کی publish شدہ app دوبارہ publish کرتے ہوئے بھی چلتی رہتی ہے۔

Mythex · Pricing · AI کے ساتھ کچھ بھی بنائیں · ویب سائٹ اور ایپ ٹیمپلیٹس · Mythex کا موازنہ · AI سے ایپ بنانے کی اصطلاحات · AI سے ایپ بنانے کے مفت ٹولز · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)