RFC-0060:錯誤處理

RFC-0060:錯誤處理
狀態已接受
區域
  • FIDL
說明

API 經常需要表示無法成功完成要求。通常有一些與錯誤相關聯的實用背景資訊,可讓呼叫端採取修正動作。這麼做建議使用一個語法,讓 FIDL 介面說明錯誤回報方式。

作者
提交日期 (年/月)2018-09-18
審查日期 (年/月)2018-12-06

摘要

API 經常需要表示無法成功完成要求。通常有一些與錯誤相關的實用背景資訊,可讓呼叫端採取修正動作。這提供了可讓 FIDL 介面描述錯誤回報方式的語法。

提振精神

大多數程式設計語言都提供例外狀況、Futures/Promises、結果類型或錯誤類型等錯誤處理結構。API 是以不支援的語言編寫的 API,通常會制定自己的慣例,例如 errnozx_status_tGError

FIDL 方法可以傳回多個值,因此一個方法可能會同時傳回值和錯誤代碼,但這是以臨時的方式執行。通常介面作者會先將錯誤代碼置於方法結果之前,但約有 20% 的時間是在方法產生結果之前。介面有時會傳回包含狀態碼和結果的 struct。狀態會以 boolintenumstringstruct 表示。

這種多元的 API 對開發人員難以理解。 缺少可區分方法與錯誤資訊的明確語法,因此無法產生慣用繫結。

設計

我們會擴充 FIDL 方法語法,讓介面描述不同的「結果」傳回類型和 error 傳回類型。事件一律不會包含錯誤類型。 語法如下所示:

interface Example {
  // This method returns no values, failures or completion.
  1: NoReturn();

  // This method returns no values or failures but informs
  // clients of completion.
  2: Completion() -> ();

  // This method returns a single value.
  3: SingleValue() -> (int32 result);

  // This method returns multiple values.
  4: MultipleValue() -> (int32 foo, string bar);

  // This method doesn't return any values but can indicate a
  // failure reason.
  5: CanFail() -> () error int32;

  // This method can succeed with a result or fail with a reason.
  6: WinOrLose() -> (string result) error ExampleError;
};

未宣告錯誤類型的方法會序列化並繫結於現況。傳回引數會編碼為 FIDL struct

宣告錯誤類型的方法會序列化為結果和錯誤傳回類型的 FIDL 聯集。因此,例如:

interface Example {
  1: Method() -> (string result, string other_result) error int32;
};

正確的編碼方式如下:

struct ExampleMethodResult {
  string result;
  string other_result;
};
[Result]
union ExampleMethodReturn {
  ExampleMethodResult result;
  int32 err;
};
interface Example {
  1: Method() -> (ExampleMethodReturn return);
};

錯誤類型必須是 int32uint32 或其中一種類型的 enum

所有現有介面都將與原始碼及二進位檔相容,但在理想情況下,這些介面會改用新的錯誤語法。

在 FIDL IR 中,代表結果或錯誤的聯集會與其他聯集分開,因為前端編譯器會將 [Result] 屬性附加至這些聯集。現有的語言繫結仍會繼續運作,但您可以進行更新,以便支援代表失敗方法呼叫的慣用語言功能。

我們建議 Dart 透過 Future 錯誤傳回失敗。 這些應該是 package:fidl 中定義的特殊 Error 類型的子類別,以便應用程式層級錯誤能夠輕鬆與繫結和通訊協定錯誤區分。

Rust 應使用 std::result::Result。C++ 可能會使用 std::expected,但若這變成實際存在,我們就能實作足夠的提案來滿足 FIDL 的需求。Go 繫結應使用自訂錯誤類型來處理錯誤傳回。

導入策略

這項操作會在後續步驟中實作:

  • 更新 fidlc 以支援新的語法。
  • 請確認定義了正確的編碼。
  • 更新 FIDL 語言說明文件。
  • 更新繫結以使用更慣用的錯誤處理機制。
  • 請更新 FIDL 相容性測試介面來測試錯誤,並支援所有語言繫結。
  • 驗證語言繫結是否正確互通。
  • 更新說明文件。
  • 建議介面作者改善介面,以便使用錯誤傳回類型。

說明文件與範例

這是 FIDL 的重大異動。 您必須更新語言無線格式說明文件,說明新的語法及其序列化方式。您必須更新 FIDL 教學課程,提供如何正確使用錯誤傳回的範例。您必須更新 API 技術評分量表,才能說明這項功能的正確使用方式。

回溯相容性

大部分的現有的 FIDL 介面仍與這項變更相容。 唯一的破壞性變更是 error 成為保留字詞。

效能

效能對於效能的影響應該幾乎有限。

安全性

將錯誤報告語意標準化,可簡化呼叫 FIDL 方法的程式碼。明確程度勝過隱含量。

測試

這需要針對 fidlc、相容性測試,以及可能的語言繫結特定測試進行測試,確保繫結符合語言原則。

缺點、替代方案和未知

這會增加程式語言的複雜度,但這只是簡單說明已在介面中以隱含方式表達的語意。

本提案不涵蓋的建議是使用標準錯誤列舉來說明錯誤類別,並提示呼叫端說明如何繼續。此模式對 errnozx_status_tHTTP 狀態碼很常見。這些示例會盡量提供更多細節,超出我們認為可適當運用。 grpc_status_code 是更好的模型,擷取高階錯誤。我們考慮在標準 FIDL 程式庫中加入一般錯誤列舉,介面作者可以選擇使用,而不是自行編寫。

我們已經廣泛探討如何排除傳輸層級 FIDL 錯誤 (例如訊息剖析失敗) 的方法 (例如找不到記錄)。目前所有傳輸層級 FIDL 錯誤都會導致管道關閉,因此沒有可折疊的錯誤代碼。我們希望能夠從這些錯誤中復原,但會在未來的 FTP 提出。將錯誤保持在 32 位元值可帶來許多錯誤折疊的機會。

本提案的較舊版本讓錯誤成為任意資料類型。 這有促進反模式 (例如傳回錯誤訊息字串) 的反對模式,而我們的靈活性可能有限,因為我們是設法依面向調整錯誤,並重新檢查錯誤折疊情形。我們目前採用較為保守的錯誤呈現方式。

先前的圖片和參考資料