[Effect-ts][Guides][Error Management]
Two Types of Errors
エラーには、想定されてエラーと想定外のエラーがある。
- 想定されるエラーは、ドメインの一部として制御フローに組み込まれる
- 想定外のエラーは、キャッチされない例外のようなもの
Effectでは、想定外のエラーについても多くの情報を提供できるように仕組みを作っている。
Expected Errors
- 想定されるエラーをEffectではどのように表現するか
- 堅牢で包括的なエラー管理為にEffectが提供するツール
について学ぶ。
豆知識
_tag
などの識別子フィールドを追加することで、TypeScriptに別のオブジェクトとして認識させることができる。
Effect<never, HttpError, never>
このように、型から、どういったエラーが発生するかを確認することができる。
Error Tracking
programの型は以下になる。
Effect<string, FooError | BarError, never>
F#なんかだと、同じパイプライン内で、別のエラーを出力すると型が違うというエラーになる。
が、TypeScriptだと、勝手にユニオン型にするのですね。
リフトする必要がないので、手間が省ける反面、勘違いやミスで予期しないエラーを残してしまうことがありそう(変換忘れとか)。
Short-Circuiting
エラーが発生したら、後の処理はスキップされる。
Catching all Errors
either
either関数を呼び出すことで、以下の型に変換される。
※Effect型のままだし、Successに、Either<A, E>が入って、Errorがneverになっている点に注意。
Effect<A, E, R> -> Effect<Either<A, E>, never, R>
また、Either型は、左側がRight、右側がLeft
catchAll
エラーが発生していたら処理する、という関数らしい。
※すべてのエラーを一律に処理するのでAllらしい。
catchSome
エラーの中で、条件に合致したものを処理する。
処理しない場合もあるので、Effectの型は変わらない。
- 処理する場合、Option.some(effect)
- 処理しない場合、Option.none()
catchIf
catchSomeとほぼ同じ。
catchTag
すべてのエラーがタグ付けされていれば、この関数でハンドリングできる。
何らか事情がなければ、この方法一択な気がする。
注意:読み取り専用の_tag識別フィールドが必要
catchTags
catchTagを複数書く場合は、こっちを使った方が可読性が上がる。
Unexpected Errors
Creating Unrecoverable Errors
回復不能なエラーが発生した時に、Effectを終了させる。
die / dieMessage
- die:例外を発生させる
- dieMessage:RuntimeExceptionを発生させる
関数シグネチャが信用できるものになるように、例外を発生させない方針だったはずだが。
おそらくは、アプリケーションの最上位レベルの関数のみでの利用を想定しているのでしょう。
orDie
受け取ったEffectがエラーだったら、例外を出して終了する。正常だったら、何もしない。
orDieWith
orDieとの違いは、エラーをそのまま例外にするではなく、加工することができる、ということ。
Catching
以下の関数は、エラーに関する情報を伝達するために、Effectと外部システムの境界でのみ利用することを想定している。
catchAllDefect
dieなどで、例外を吐かせようとしていても、すべて拾ってしまうため例外にならない。
Errorには反応しないので注意。
catchAllの例外版
catchSomeDefect
catchSomeの例外版
Fallback
orElse
エラーの時に処理を適用する。正常ならば実行されない。
orElseFail / orElseSucceed
- orElseFail:エラーなら、別のエラーへ置き換える
- orElseSucceed:えらーなら、成功に置き換える
firstSuccessOf
Effectのリストを与えられたら、最初に成功したものの結果を返す。
リストが空だと、例外が発生する。
リトライが発生するようなもの用か。
Matching
Effect型にも他の型(OptionやExit)のようにmatchがある。
match
成功と失敗のケースを同時に扱うことができる。
成功や失敗のケースを無視することもできる。
その場合には、Function
モジュールのconstVoid
関数を利用することができる。
全部を無視する場合には、Effect.ignoreを使ってもよい。
matchEffect
マッチした後に、追加の副作用を実行したい場合には、こちらを利用する。
matchCause / matchCauseEffect
正常、エラーに加えて、例外も扱うことができる。
Retrying
ネットワークの瞬断のような取り立てて原因調査をする必要がなく、防ぎようもない失敗に対してはリトライするようにしておくと色々と都合がよい、ということらしい。
retry
Effect.retry(effect, policy)
policyには、どうリトライするのかを設定する。
retry n times
retry(effect, { times: 5 })
policyを設定するのが面倒な場合、以下のような方法で、直ちに5回繰り返す処理を書ける。
retryOrElse
リトライを(一定回数など)行っても、エラーだった場合に実行する処理を定義することができる。