2016-11-17 1 views
4

を扱う成功事例とエラー(私が参照として別の質問を引用したい:How do I elegantly check many conditions in Erlang?アーラン:トランザクションとして

「エラー処理から分離成功事例コード」の一般的な形式があるように思わ:

try 
    ok = do_x(), 
    ... 
    ok = do_y() 
catch 
    error:{badmatch, x_failure} -> do_something1(); 
    ... 
    error:{badmatch, y_failure} -> do_something2(); 

try節の関数が、ファイルの書き込み、ネットワークパケットの送信、データベースへの行の書き込みなどの副作用を伴う何らかの処理を行う場合、このパターンを使用する方法はありますか? catch節に「ロールバック」用の汎用パターンがありますか?例:

try 
    %How to make this whole block a transaction? 
    ok = step_1_write_file(), 
    ok = step_2_write_database(), 
    ok = step_3_send_packet(), 
    ... 
catch 
    error:{badmatch, database_failure} -> clean_up_step_1() %delete file? 
    error:{badmatch, sendpacket_failure} -> clean_up_step_1_and_2() %?? 

実行する必要があるクリーンアップが失敗したtryブロックのステップに依存しているところエラーハンドリングは、有償取得するように思えます。私は個人的に渡すことで、そのようなアルゴリズムをプログラミングすることを学んだ

+3

成功_typing_はここでは関連していないようです。 –

+0

@AlexeyRomanov question title edited – Tommy

答えて

3

失敗した句の前のtryブロックで成功のステップは、「 ``巻き戻されているのに対し、トランザクションとしてこれを扱う一般的なプログラミングパターンは、ありますか?あなたが見ることができるように、このリストには、本体を使用して評価するので、

noop() -> ok. 

transaction([{Fun, Rollback} | Rest]) -> 
    try 
     {ok, Result} = Fun(), 
     [Result | transaction(Rest)] 
    catch Type:Reason -> 
     Rollback(), 
     erlang:raise(Type, Reason, erlang:get_stacktrace()) 
    end; 
transaction([Fun | Rest]) -> 
    % not every action require cleanup on error 
    transaction([{Fun, fun noop/0} | Rest]); 
transaction([]) -> []. 


main() -> 
    Actions = [ 
     {fun write_file/0, fun cleanup_file/0}, 
     {fun write_database/0, fun cleanup_database/0}, 
     fun do_safe_thing/0, 
     {fun send_packet/0, fun cancel_send_packet/0}, 
    ], 
    transaction(Actions). 

:「バリ」と、optionaly、いくつかの一般的な反復機能に「ファイナライザ」のリスト

だから、あなたの場合は次のようにプログラムすることができます再帰、反復このリストを介してスタックが呼び出され、これらの関数のいずれかが落ちるとスタックが巻き戻され、各クリーンアップ関数が逆の順序で呼び出されます。

たとえば、do_safe_ting/0になると、クリーンアップ機能noop/0cleanup_database/0、およびcleanup_file/0がこの順番で呼び出されます。

もちろん、これは例外を再スローするのではなく、例えば{ok, Result}{error, Reason}を返すことによって、異なる方法でプログラムすることができます。実装の詳細です。

+0

私の場合、あなたの例を使って 'send_packet'が失敗した場合、私はすべての前のステップをロールバックしたいと思います。私は、すべてのロールバック関数のリストを渡してリストに追加し続けることができると思います。 – Tommy

+0

@Tommy Actualy、erlang:raiseはスタックによってキャッチダウンされるので、それぞれの以前のロールバック関数が呼び出されます – seriyPS

関連する問題