RFC-0060:錯誤處理 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | API 經常需要表示無法成功完成要求。通常有一些與錯誤相關聯的實用背景資訊,可讓呼叫端採取修正動作。這麼做建議使用一個語法,讓 FIDL 介面說明錯誤回報方式。 |
作者 | |
提交日期 (年/月) | 2018-09-18 |
審查日期 (年/月) | 2018-12-06 |
摘要
API 經常需要表示無法成功完成要求。通常有一些與錯誤相關的實用背景資訊,可讓呼叫端採取修正動作。這提供了可讓 FIDL 介面描述錯誤回報方式的語法。
提振精神
大多數程式設計語言都提供例外狀況、Futures/Promises、結果類型或錯誤類型等錯誤處理結構。API 是以不支援的語言編寫的 API,通常會制定自己的慣例,例如 errno
、zx_status_t
和 GError
。
FIDL 方法可以傳回多個值,因此一個方法可能會同時傳回值和錯誤代碼,但這是以臨時的方式執行。通常介面作者會先將錯誤代碼置於方法結果之前,但約有 20% 的時間是在方法產生結果之前。介面有時會傳回包含狀態碼和結果的 struct
。狀態會以 bool
、int
、enum
、string
和 struct
表示。
這種多元的 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);
};
錯誤類型必須是 int32
、uint32
或其中一種類型的 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
、相容性測試,以及可能的語言繫結特定測試進行測試,確保繫結符合語言原則。
缺點、替代方案和未知
這會增加程式語言的複雜度,但這只是簡單說明已在介面中以隱含方式表達的語意。
本提案不涵蓋的建議是使用標準錯誤列舉來說明錯誤類別,並提示呼叫端說明如何繼續。此模式對 errno
、zx_status_t
和 HTTP 狀態碼很常見。這些示例會盡量提供更多細節,超出我們認為可適當運用。
grpc_status_code
是更好的模型,擷取高階錯誤。我們考慮在標準 FIDL 程式庫中加入一般錯誤列舉,介面作者可以選擇使用,而不是自行編寫。
我們已經廣泛探討如何排除傳輸層級 FIDL 錯誤 (例如訊息剖析失敗) 的方法 (例如找不到記錄)。目前所有傳輸層級 FIDL 錯誤都會導致管道關閉,因此沒有可折疊的錯誤代碼。我們希望能夠從這些錯誤中復原,但會在未來的 FTP 提出。將錯誤保持在 32 位元值可帶來許多錯誤折疊的機會。
本提案的較舊版本讓錯誤成為任意資料類型。 這有促進反模式 (例如傳回錯誤訊息字串) 的反對模式,而我們的靈活性可能有限,因為我們是設法依面向調整錯誤,並重新檢查錯誤折疊情形。我們目前採用較為保守的錯誤呈現方式。