« CartonConference行ってきた | メイン | DBIx::Schema::DSLがWeek's winnerになりました »

2013年3月 3日

DBIx::TransactionManager::EndHookが便利だけどCPANに上がっていない件

後輩だか先輩だかわからないsoh335さんが作った DBIx::TransactionManager::EndHook が地味にかなり便利。

入れ子になったtransactionでcommitが走った時に走らせたい処理を登録できます。 RDBだけで完結しない処理(ログやKVS連携等)を書きたい時に有用です。

何が嬉しいかは、335さんのエントリにも書いてあるんです が、例えば、ひとつのトランザクションの中で、

  1. アイテム付与メソッド
  2. ボーナス付与メソッド

みたいなメソッドを呼び出されていて、それぞれのメソッドの中でログを投げていた りとかするとします。コードにすると以下のような感じ。 (Tengっぽく書いてますが、DBIx::TransactionManager直でも全然構いません)

my $txn = $teng->txn_scope;

$user->take_item($item);
$user->try_to_take_bonus; # ここで死ぬと困る

$txn->commit;

...
sub take_item {
    my ($self, $item) = @_;
    $self->items->add($item);
    log('take item!');
}

この場合、もしtry_to_take_bonusの中で例外が発生したりrollbakeが呼ばれたりすると、 take_itemの処理も正しくロールバックされるのですが、take_itemの中でログ書き込み 処理とかが行われているとそこまでは正しく巻き戻すことはできません。

それじゃ困るってことで、DBIx::TransactionManager::EndHookの出番。先ほどの take_itemを以下のように書き換えます。

use DBIx::TransactionManager::EndHook;
sub take_item {
    my ($self, $item) = @_;
    $self->items->add($item);
    $teng->transaction_manager->add_end_hook(sub {
        log('take item!');
    });
}

このようにすることで、commitが走った後にログ書き込みをすることができます。

ログなんかの他にもcommitが走ってから確実にRedisのランキングデータを更新したい みたいな場合にも有用です。

僕なんかは「Rollbackとかめったに起こらないし、そこで多少ログ間違えて吐いても良 くね?」くらいに思っていたのですが、soh335先生はそこが気になったみたいでこうい う痒いところに手が届くモジュールが出来上がりました。

DBIx::TransactionManagerのメソッドをRedifineしたりとかしてるので、CPANに上げる のをためらっているようなのですが、まあprivateメソッドを書き換えたりしているわ けじゃ無いので良いんじゃないでしょうか。不安だったら、#dbix-skinny@irc.perl.orgとかで相談したらいいんじゃないかみたいな話をしております。

soh335先生は結構細かいところが気になる人で、とにかく綺麗にテスト書かないと気がすまなかったり「わたし、気になります」ばりに質問力を発揮したりこういう痒いところに手が届く便利ツールを作ってたりするので一緒に仕事をしていて捗ります。

そんな中生まれた、Test::Cond::Deepも地味に便利です。 →Test::Cond::Deepに関するエントリ

なんか、二番煎じの宮崎あおいばかり注目を集めていて、 彼が作った有用なモジュールの情報があまり知られていないようだったので勝手に宣伝しました。

ということで、DBIx::TransactionManager::EndHookもCPANに上げてほしい。

投稿者 Songmu : 2013年3月 3日 23:39