زنده نگه داشتن چت وقتی گوشی به خواب میرود
عامل Mythex میتواند دقیقهها روی یک درخواست کار کند، و ممکن است شما از گوشی تماشا کنید — که وقتی کار میکند قفل میشود، بین برنامهها میپرد و شبکه عوض میکند. دو باگ باعث خراب شدن این وضعیت میشدند. در یکی، چت هر سیگنال «صفحه دوباره قابل مشاهده است» را بهعنوان دلیلی میگرفت که اتصالش قطع شده، و در حلقه میافتاد تا روی «در حال اتصال…» بماند. در دیگری، گوشیای که اولین پاسخ یک چت تازه را خواب مانده بود، با فقط چند تکهی اول آن برمیگشت، تا وقتی که صفحه دستی رفرش میشد. هر دو رفع شدهاند.
چگونه چت یک نوبت در حال اجرا را دنبال میکند
در حین کار عامل، چت یک استریم از سرورهای ما باز نگه میدارد: هر گام — یک فکر، یک فراخوانی ابزار، یک تکه از پاسخ — بهصورت یک رویداد میرسد. اگر استریم قطع شود، چت دوباره وصل میشود و سرور رویدادهای اخیر را از یک بافر که ۱۲۰ ثانیهی آخر را نگه میدارد پخش مجدد میکند. وقتی نوبت تمام میشود، چت از سرور تاریخچهی ذخیرهشده را هم میخواهد و آنچه نشان داده بود را با آنچه ذخیره شده تطبیق میدهد. این گام آخر هر چیزی که استریم از دست داده را میگیرد.
برای تشخیص اتصال زنده از مرده وقتی هیچ اتفاقی نمیافتد، سرور هر ۱۵ ثانیه یک «ping» کوچک میفرستد.
باگ ۱: بیدار شدن یک استریم سالم را کشت
مرورگرها به صفحه میگویند وقتی دوباره قابل مشاهده شده: بعد از عوض کردن تب، بعد از باز شدن قفل صفحه. ما این را نشانهای گرفته بودیم که اتصال را بررسی کنیم — و در عمل، استریم را قطع و دوباره وصل میکردیم، با این فرض که در مدت پنهان بودن مرده است.
در گوشیها و مرورگرهای تعبیهشده، این رویدادها بسیار بیشتر از مرگ استریمها رخ میدهند — هر تعویض تب، هر باز شدن قفل، و در بعضی مرورگرهای تعبیهشده هر چند ثانیه. هر کدام یک استریم کاملاً سالم را قطع میکرد. چت دوباره وصل میشد، پخش مجدد میگرفت، دوباره قطع میشد، و در نهایت روی «در حال اتصال…» میماند. سپس میگفت نوبت تمام شده در حالی که عامل هنوز کار میکرد.
راهحل: استریم را بر اساس اینکه حرف میزند قضاوت کن
چت حالا ثبت میکند که استریم هر پروژه آخرین بار کی چیزی دریافت کرده — چه رویداد و چه pingهای ۱۵ ثانیهای. سیگنال «دوباره قابل مشاهده» فقط استریمی را قطع میکند که ۲۵ ثانیه ساکت بوده: بیشتر از فاصلهی ping بهعلاوهی یک پرش کند شبکه، پس یک استریم زنده هرگز واجد شرایط نمیشود. تستها بررسی میکنند که یک ping نشانهی زنده بودن حساب شود، و استریمی که همین الان ping زده مرده فرض نشود.
قاعدهای که از آن گرفتیم: قابل مشاهده بودن یک صفحه چیزی دربارهی خود صفحه میگوید، نه دربارهی اتصال شبکه. از خود اتصال بپرسید.
باگ ۲: نیمی از پاسخ بعد از بیدار شدن گوشی
این را هر بار در شبیهساز iOS میتوانستیم بازتولید کنیم:
- یک چت تازه شروع کنید و درخواستی بفرستید که مدتی طول میکشد.
- بگذارید گوشی در حین ساخت بخوابد.
- بعد از تمام شدن نوبت و منقضی شدن بافر دو دقیقهای پخش مجدد برگردید.
چت چند بلوک اول پاسخ را نشان میداد، با علامت «تمام شده» — و تا وقتی صفحه را رفرش نمیکردید، همانطور میماند.
چرا
یک چت تازه تا وقتی اولین پیام آن را نساخته، رشتهای ندارد — یعنی مکالمهی ذخیرهشدهاش. این در داخل تابع ارسال رخ میدهد، بعد از اینکه ارسال گام تطبیق را از قبل گرفته بود، و آن گام هنوز فکر میکرد رشتهای وجود ندارد. پس در پایان اولین نوبت یک چت تازه، تطبیق رشتهای نمیدید و بیسروصدا بدون کاری برمیگشت.
معمولاً کسی متوجه نمیشد، چون استریم کل نوبت را در هر حال تحویل داده بود. اما گوشیای که در طول نوبت خوابیده بود و بعد از منقضی شدن بافر پخش مجدد ۱۲۰ ثانیهای برگشته بود، نمیتوانست رویدادهای گمشده را از استریم بگیرد — و تطبیقی که باید شکاف را پر میکرد هرگز اجرا نشده بود.
راهحل
- ارسال به تطبیق میگوید نوبت متعلق به کدام رشته است، پس نوبت اول یک چت تازه مثل هر نوبت دیگری تطبیق میشود. اگر تا رسیدن جواب، چت دیگری باز کرده باشید، نتیجه دور ریخته میشود تا در جای اشتباهی نشان داده نشود.
- تطبیق ناموفق دوباره امتحان میشود. گوشیای که با اتصال بد بیدار میشود ممکن است ببیند نوبت تمام شده و سپس نتواند آن را دریافت کند. حالا این به خاطر سپرده میشود، و چت وقتی تب دوباره نشان داده شود یا شبکه برگردد، دوباره میپرسد.
- «مدت کار» صادقانه است. هر پاسخ نشان میدهد عامل چقدر کار کرده. اگر تب هرگز پیام پایان نوبت سرور را ندیده بود، پیشتر آن را از ساعت خودش پر میکرد — که از لحظهی ارسال تا بیدار شدن گوشی میشمرد، شامل زمانی که دور بودید. این عدد حالا تخمین علامت میخورد، و وقتی تاریخچه برسد با مدت ذخیرهشده جایگزین میشود.
آنچه از آن یاد گرفتیم
- روی دستگاهی که مردم واقعاً استفاده میکنند و به همان شیوهای که استفاده میکنند تست کنید. هر دو باگ در فاصلهی بین «استریمی که کار میکند» و «گوشیای در جیب» زندگی میکردند.
- پشتیبانی که هرگز اجرا نمیشود، پشتیبان نیست. گام تطبیق برای گرفتن دقیقاً همین حالت وجود داشت، و بیصدا از آن رد میشد.
- خود بازیابی را هم دوباره امتحان کنید. لحظهای که گوشی بیدار میشود اغلب همان لحظهای است که اتصالش در بدترین حالت است.
- یک حدس را بهعنوان واقعیت نشان ندهید. مدتی که از ساعت اشتباه آمده، بدتر از هیچ است؛ آن را برچسب بزنید یا جایگزینش کنید.
همین کار چند چیزی را که در حین اجرای نوبت میبینید هم مرتب کرد: مراحل پوسته با دستوری که کار واقعی را انجام میدهد برچسب میخورند نه cd، اسکرینشاتهای داخل چت گوشهی بالا-چپ صفحه را نگه میدارند و در ستون جا میشوند، و یک پروژهی تازه نام تولیدشدهاش را بدون رفرش میگیرد.
اگر برنامهی خودتان را برای گوشی میسازید، راهنماهای ما دربارهٔ ساخت وباپ سازگار با موبایل و اپ بومی در برابر PWA مبانی را پوشش میدهند. دربارهٔ خود چت در مستندات چت بیشتر بخوانید.