読者です 読者をやめる 読者になる 読者になる

Catalystのfinalize処理

Catalyst で DB への commit / rollback のためにこんなコードを書いていて……

package MyWebApp;
# 略
sub finalize {
    my $c = shift;
    my $r = $c->NEXT::finalize(@_);

    if (正常終了) {
        $dbh->commit;
    }
    else {
        $dbh->rollback;
    }
    return $r;
}

他の finalize が全部終わってから、エラーがなければ commit、エラーがあったら rollback をしよう、という意図だったんですけど。

いわゆる PRG パターン (POST-Redirect-GET) をやった場合に、先の POST で更新されているはずのデータが GET で読み取れない、というケースが発覚。

上の書き方だと commit の前に他の finalize が実行されて、そこでレスポンスがクライアントに送られてしまうんですね。先に。
そのレスポンス (リダイレクト指示) を受け取ったクライアントは GET を発行して、新しいトランザクションを開始してデータを読むわけですが、運が悪いと、その時点ではまだ先の POST 処理のトランザクションが commit されていない場合がある。

ということで、以下のように、先にトランザクションを完了させてから NEXT::finalize を呼べばいいんですが……

sub finalize {
    my $c = shift;
    if (正常終了) {
        $dbh->commit;
    }
    else {
        $dbh->rollback;
    }
    return $c->NEXT::finalize(@_);
}

そもそもこういう DB の commit 処理って、finalize でやるべきものなのかな、という疑問も。どうするのが一般的なんでしょうか……