跳到內容

Flag 如何送達你的應用程式

你的應用程式不會每次檢查 flag 都呼叫 FortressFlag。Flag 的讀取是本地的:即時、離線也安全、路徑上沒有網路。在網路上傳輸的是定期輪詢,而那次輪詢抓取什麼,取決於你在兩個平面中的哪一個。

用戶端平面:你的應用程式拿到答案,而不是規則

Section titled “用戶端平面:你的應用程式拿到答案,而不是規則”

iOS、Android 和 Web SDK 使用用戶端平面。裝置送出它的身分和標籤;FortressFlag 在伺服器端評估你的鎖定規則,只回傳這台裝置的值:一個像 {"new-checkout": true, "dark-mode": false} 的小型對應表。

裝置永遠不會收到你的規則。這是刻意的,而且有兩層理由:你的鎖定邏輯(「測試版分群」、「內部裝置」)是你的業務,不該裝進任何人都能從應用程式二進位檔拆出來的東西裡;而且酬載能保持極小。

用戶端平面以用戶端金鑰(ffc_…)進行驗證,它隨你的應用程式出貨,而且設計上就是公開的。細節見金鑰。

伺服器平面:你的後端拿到 ruleset

Section titled “伺服器平面:你的後端拿到 ruleset”

Go SDK 使用伺服器平面。你的伺服器為一個專案 + 環境下載完整的 ruleset(種類、預設值、規則,區隔已經攤平進去),並在它自己的行程內評估 flag。一次 flag 檢查就是對記憶體中既有資料的一次函式呼叫:每次檢查不走網路、沒有每個請求的延遲,而且不管處理多少請求,一次輪詢就服務整個行程。

因為 ruleset 包含你的鎖定規則,這個平面放在一把伺服器金鑰(ffs_…)後面:一個貨真價實的機密,要像資料庫密碼一樣對待。而既然你的規則會送達每一台持有該金鑰的伺服器,推論就由你來套用:別把機密或你的使用者的個人資料放進規則條件裡。

這個平面上沒有裝置身分。你的程式碼在每次評估時傳入一個內容鍵(使用者 ID、工作階段 ID,隨你要依什麼分桶),發布的算術用它的方式和用戶端平面用裝置 ID 的方式完全一樣,所以同樣的輸入不管由哪個平面評估,都落在同一個分群。

兩個平面都按間隔輪詢,也都使用條件式請求:每個回應帶著一個驗證器(ETag),當自上次輪詢以來什麼都沒變,答案就是一個極小的「沒有變動」:沒有內容主體、不重新評估。一群沒有在改 flag 的裝置,穩定狀態就是一連串幾乎免費的確認。

當你真的改了什麼(一次切換、一條規則、一個排程觸發),下一次輪詢會完整抓取。實際上,一次變更會在大約一分鐘內送達在線的用戶端裝置。

(一個計費備註:「沒有變動」的回應仍然算作每月活躍裝置計數的活動,但記得,一台裝置不管輪詢多頻繁,每月只算一次。)

FortressFlag 的故障絕不能拖垮你的應用程式。每個 SDK 都把最後收到的值保存在持久的本地快取裡,並透過同一條串接解析 flag:

  1. 最後收到的值,即使來自上一次執行。一台離線一個月的裝置提供它最後看到的內容;寧可過時,也不要意外的功能倒退。
  2. 你的程式碼的預設值(呼叫處的值),在從來沒收到任何東西時使用。(用戶端 SDK 對沒有預設值的布林讀取,最終落在 false。)

兩個值得知道的後果:

  • 被撤銷或失效的憑證不會弄壞你的應用程式。SDK 繼續提供它的快取,並持續重試。錯誤永遠不會透過 flag 讀取觸及你的使用者。
  • SDK 無法驗證的酬載會被當作根本沒有酬載來處理。每一個回應都有簽章,SDK 會在任何東西改變之前檢查簽章:見 Payload 簽章。
  • 封存 flag 真的會把它關掉。當一個 flag 從酬載中消失,SDK 會在同一次輪詢把它從即時值和快取中一併移除:大約一分鐘內,各地的在線裝置都解析成你的程式碼的預設值。快取永遠不會保留已移除的 flag,否則封存就無法徹底結束一次發布。