22
処理全体の例外を透過的に 捕捉する いくつかの考え OGATA Tetsuji (@xtetsuji) 2015/01/31 Hachioji.pm#46

処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

Embed Size (px)

Citation preview

Page 1: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

処理全体の例外を透過的に 捕捉するいくつかの考え

OGATA Tetsuji (@xtetsuji) 2015/01/31 Hachioji.pm#46

Page 2: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

自己紹介

• 尾形 鉄次 (OGATA Tetsuji)

• Twitter: @xtetsuji

• Blog: http://post.tetsuji.jp/

• 今年もよろしくお願いします。いろいろやります。

• 現在無職です

Page 3: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

2015年1月31日

Page 4: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

1年前の2014年1月31日に 株式会社fonfunを退職

Page 5: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

そして色々事情があって 次の会社も退職

Page 6: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

そして無職

Page 7: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

できた時間で、療養と いくつかの活動を進行中

Page 8: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

思索がはかどる

Page 9: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

fonfun時代の最後の上司のコードテンプレを思い出した

Page 10: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

#!/usr/bin/perluse strict;use warnings;use Project::CGI;...;{ ## 無名ブロック始まりmy $cgi = new Project::CGI;my $rv = eval { ...; # 一般的な処理};if( $@ || !defined $rv ) { ...; # 例外処理}} ## 無名ブロック終わりexit;

Page 11: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

このコードテンプレート

• Perl CGIとしてのmod_perlの高速化環境のコード(ModPerl::RegistryPrefork)

• 処理のほとんどを eval { … }; でくくっている

• 処理の最後で例外処理

• ブロックevalの中にブロックevalがあることもあるけれど、続ける場合は $@ に注意するとかはある

Page 12: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

ときどき言っていたこと

• 私「このやり方、一つの方法として面白いんですけど、毎回書くのダルくないですか?」

• 上司「ダルいね」

• 私「これモジュールにできそうなものですけれど」

• 上司「別にいいよ」

Page 13: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

やり方考えてみた

• スクリプト中にCATCHという関数があれば、スクリプトで例外が発生したときにそいつが呼ばれるといいな

• ENDもsubが要らないだけの特殊サブルーチンだし、CATCH関数の存在もuseしたモジュールから確認することができるから、なんかうまくいきそう

Page 14: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

呼び出し側use Try::ProecessCatch;

...;

sub CATCH { my $e = shift; if ( $e ) { ...; }}

Page 15: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

モジュール側package Try::ProcessCatch; # 仮

sub import { my ($package) = caller; no strict 'refs'; my $end_cb = ${"$package\::"}{END} || sub {}; # あれば my $catch_cb = ${"$package\::"}{CAHTCH} || sub {}; # 独自 my $new_end_cb = sub { $end_cb->(); $catch_cb->($@); } ${"$package\::"}{END} = $new_end_cb;}

1;

Page 16: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

これで

• callerで呼び出し元パッケージ名を取得してシンボルテーブルをいじる

• $@ は真のグローバル変数だからこれでいい

• …はずなんだけどうまくいかない

Page 17: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

コンパイル時の順序問題

• use も 関数定義も同じコンパイル時なので、上に書けば当然 use Try::ProcessCatch した段階では END も CATCH も見つけられない

• かといって、use は END や CATCH の下に書いてねっていうのもダサい…

Page 18: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

そもそもmod_perlで動かないし• mod_perlでのENDは、HTTPリクエスト処理の終了時ではなく、Apacheのプロセスの終了時だった!

• これは ModPerl::RegistryPrefork を改造するのが早い

• mod_perl2だと、ModPerl::RegistryCooker から簡単に拡張できて美味しい → この実装は大変そうだけど

• 逆にmod_perl2だと順序関係ないし、これでいいのか!

Page 19: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

PSGIファイルだと

• 事情は一緒っぽい

• コードのコンパイル部分(サンドボックス作成部分)に介入するのは泥沼化しそう(ここがmod_perlとの違い)

• psgix.harakiriはクリーンナップフェーズだろうし、ちょっと意味合いが違う

• 簡単そうに見えて、意外に難しいのは自分の勉強不足

Page 20: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

課題

• コンパイルフェーズで上から下へ解釈されるものの遅延評価みたいなことはできるんだろうか

• ModPerl::ReigstryCooker拡張を頑張る

• Plackのソースコードを理解する

Page 21: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

アイデアお待ちしています

Page 22: 処理全体の例外を透過的に捕捉するいくつかの考え #hachiojipm

おしまい