網誌

失敗的重新發佈絕不會刪除運作中的後端

9 月 25 日,一次失敗的重新發佈刪除了一個應用程式的後端。該後端已經運作了大約兩個半小時。撤銷失敗發佈的程式碼,移除了該次發佈所觸及的每一個伺服器應用程式,包括那些在發佈開始前已經在提供服務的應用程式。現在,只有由發佈新建的應用程式才會被刪除;原本已存在的應用程式,會被還原到它在發佈前運行的確切版本。當日另外兩項後續修正,確保了當託管平台自己的部署工具失敗時,撤銷程序同樣會執行,並且健康的應用程式不會因為正在休眠而被判定為失敗。

後端如何發佈

當你的 Mythex 應用程式有後端(即 API 或伺服器,而不只是靜態檔案)時,發佈會先用 Dockerfile(一份將應用程式打包成映像檔的指令清單)建構它,然後把該映像檔部署到我們託管平台的機器上。之後,健康檢查會等待新版本真正啟動並穩定運行,發佈才會被標示為上線。

如果過程中任何一步失敗,就會執行回滾來撤銷變更。正確處理回滾,比發佈過程中幾乎所有其他環節都更重要,因為它正正是在有事情已經出錯的時候才會運行。

問題一:回滾刪除了本應還原的東西

回滾程序會記錄一份清單,列出該次發佈部署到的伺服器應用程式,失敗時就把清單上的每一個都摧毀。對於首次發佈來說,這樣做是正確的:應用程式是剛剛才建立的,沒有任何東西依賴它,刪除之後一切就回到原來的樣子。

但對於重新發佈來說,這就完全錯誤。應用程式本來已經存在,並且正在為真實的訪客提供服務。9 月 25 日,一個已經上線約兩個半小時的應用程式 API,就被一次失敗的重新發佈刪除了。

同一段程式碼裡還藏著另一個失敗模式。如果刪除沒有成功,壞掉的新映像檔就會留在機器上,而我們卻告訴擁有者他們目前的網站仍然在線。健康檢查失敗的時候,新映像檔其實已經部署到每一部機器上了。什麼都不做,並不等於撤銷。

修正方法:只刪除自己建立的,其餘的還原

現在,每次發佈都會為它觸及的每個伺服器應用程式記錄:

  • 這次發佈是否建立了它,以及
  • 如果不是,它在發佈前運行的是哪個映像檔。

失敗時,每個應用程式會按以下三種方式之一處理:

  1. 由這次發佈建立: 照舊將其刪除。
  2. 原本已存在,且已知先前的映像檔: 以相同設定重新部署先前的映像檔。不需要重新建構,只是把映像檔換回去。
  3. 原本已存在,但先前的映像檔未知: 不予理會。已存在的應用程式絕不會被刪除,即使我們無法還原它。

這些規則是一個小型的純函式,並附有自己的測試,所以這項決定不會在沒有測試失敗的情況下倒退回「全部刪除」。

問題二:部署工具可能在我們記下撤銷方法之前就已失敗

那次修正之後不久,我們發現它仍有一個缺口。託管平台的部署工具會執行它自己的冒煙測試:如果新機器崩潰,它就會以錯誤結束。但它是在新映像檔已經部署到機器上之後才這樣做的。

我們的程式碼只有在工具成功返回後,才會把應用程式登記到回滾清單上。當工具本身令部署失敗時,應用程式還沒有登記在回滾清單上,因此什麼都沒有被還原。在我們的預發佈(staging)環境中,一次壞掉的重新發佈就讓壞掉的映像檔繼續提供服務。

修正方法:在開始之前先登記撤銷方法

現在,應用程式會在準備就緒、部署任何東西之前,就登記到回滾清單上,同時記下它是否是新建的以及它原本運行的映像檔。無論之後哪一步失敗,回滾都知道要還原什麼。我們在本地驗證過:一次壞掉的重新發佈在部署工具自己的冒煙測試中失敗,而先前的版本仍然繼續回應請求。

問題三:休眠中的應用程式被判定為「從未啟動」

Mythex 上的已發佈應用程式在閒置時會休眠,以節省你的額度。重新發佈後,休眠中的機器會保持停止狀態,所以健康檢查必須把它喚醒。以往它只會要求平台啟動機器一次,並且忽略回應。

9 月 25 日,那一次啟動請求沒有得到回應。一個健康的 API 在整個五分鐘的健康檢查期間都保持停止狀態,最後因為「1 部機器從未啟動(最後狀態:stopped)」而被判定為失敗。

平台有時確實會拒絕啟動請求。我們在重現問題時,平台在我們沒有刻意觸發的情況下,返回了「lease currently held」衝突;而且平台在機器正在更新時,也會拒絕啟動。

修正方法:持續請求,並敲門

健康檢查現在會:

  • 在等待期間,每 20 秒再次要求啟動已停止的機器,
  • 記錄平台拒絕時給出的回應,以及
  • 向應用程式發送一個普通請求,就像訪客那樣——平台的代理會在請求到達時喚醒休眠的機器。

我們用一個第一次啟動會被拒絕的臨時應用程式,在真實的平台上重現了這個問題。修正前,發佈在 91 秒後失敗;修正後,20 秒內就完成發佈。真正在開機時崩潰的應用程式仍然會失敗,這正是應有的結果。

我們從中學到的

  • 回滾必須分清楚新建與已存在的分別。 對於你建立的東西,「撤銷」就是刪除;對於原本就存在的東西,「撤銷」就是還原。把兩者等同處理,就是保護機制刪除了運作中應用程式的原因。
  • 在行動之前先寫下如何撤銷。 如果撤銷方法只在某一步成功之後才記錄,那麼中途失敗的步驟就沒有東西可以用來撤銷。
  • 絕不要忽略你所依賴的請求的回應。 一個被忽略的「不」,就讓一個健康的應用程式變成了發佈失敗。

同一天的另一項相關修正:剛發佈後就崩潰的應用程式如何捕捉。如果發佈在你這一端失敗,請參閱文件中的發佈疑難排解。

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 简体中文 繁體中文(台灣)