$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

処理のtimeoutを簡単に書くためのSub::Timeoutというモジュールを作りました

ある処理をするときに一定以上の時間かかったらtimeoutして処理を終わりたいみたいなことをしたい時がたまにあるので、それを行うSub::Timeoutというモジュールを作りました。

https://github.com/shibayu36/p5-Sub-Timeout

使い方

use Sub::Timeout;
use HTTP::Tiny;

my $res = timeout 3.5, sub {
    HTTP::Tiny->new->get('http://example.com/foo');
};

基本的には上のように、タイムアウトしたい秒数と処理のcoderefを渡します。
上の例だと3.5秒間で処理が終わった場合、その返り値を$resとして返し、処理が終わらなかった場合、その時点で処理を打ち切って例外を投げるようにしています。例外を投げるのでその後も処理を続けたい場合は例外処理をしてください。

またタイムアウトした時の処理を、例外を出すのでなく自分で実装したい場合は3引数目でcoderefを渡すことで設定出来ます。

use Sub::Timeout;
use HTTP::Tiny;

my $res = timeout 3.5, sub {
    HTTP::Tiny->new->get('http://example.com/foo');
    sleep 4;
}, sub {
    return "timeout!";
};
warn $res; # => timeout!

この場合、タイムアウトした時に例外は投げません。

同様のモジュール

同様のモジュールにはTime::Outというモジュールがあります。
しかしこのモジュールは構成が少しいけてなかったり(なぜかlib/Out.pmに実装がある)、globalな$@へのアクセスを使ってtimeoutの検出をしたりといろいろ使いにくかったため、もう少し簡単な形に実装しなおしました。

今後

まだCPANにはあげてませんが、もう少しドキュメントなど見直したら上げたいと思っています。モジュールの名前とかインターフェースでこっちのほうがいいのではみたいな意見があれば、教えていただけるとありがたいです!

Thanks to

今回のモジュールはid:nobuoka さんとid:y_uukiさんにいろいろ意見をもらったり手伝ってもらったりしました。id:nobuoka++, id:y_uuki++

追記

Time::Out以外にも同様のモジュールあるみたいだった。shipitどうするかという感じになってきた。timeoutだけ切り出したモジュールとして出すのもありなのかどうか。