Fighting Legacy code
~本当にあったレガシーな話〜
Daisuke Maki
Japan Perl Association / LINE Corporation
お詫び
http://codezine.jp/book/modernperl2
livedoorBlog
livedoorBlog
livedoorBlog
どう実現したのか?!
tl;dr
THERE. IS. NO. SILVER. BULLET.
銀の弾丸など存在しない
orz
〜 糸冬 了 〜
tl;dr (2)
Seek, and you shall find
inside
コードベース
これまで→これから
目標
要は
ここから
こうしたい
perl upgrade
DaveArnoldPhoto.com
システム分割
Road to PSGI
Phase 1: 配信システムをリファクタリング
sub hoge {
my ($self, $mogo, $muga, $moge) = @_;
…
# warn “Got $mogo $muga $moge”;
if (! $mogo) {
# warn ‘$mogo is FALSE’
…
}
…
}
FAIL
ログ
You WILL log. Or else.
http://www.layoutsparks.com
ログ
ログ
use constant LDBLOGNG_DEBUG
=> $ENV{LDBLOGNG_DEBUG};
use Log::Minimal;
sub hoge {
my ($self, $mogo, $muga, $moge) = @_;
…
if (LDBLOGNG_DEBUG) {
debugf(“Got %s %s %s”,
$mogo, $muga, $moge);
}
if (! $mogo) {
if (LDBLOGNG_DEBUG) {
debugf(‘$mogo is TRUE’);
}
…
}
…
}
ログ
[START PSGIApp]
[START BlogMapper]
Found blog “lestrrat”, id = 1
[END BlogMApper]
[START Handler::Index]
Cache MISS for key “lestrrat…”
Generating content from DB
[END Handler::Index]
[START Deflater]
Content-Length 12345 > threshold (1096)
Going ahead with compression
[END Deflater]
[END PSGIApp]
...
ログ
tl;dr
mod_perl
mod_perl Yak Shaving
Oh mod_perl,
How do I hate thee?
Let me count the ways.
….
リファクタリング
$r の追放
sub handler : method {
my ($class, $r) = @_;
if (...) {
$r->status(404);
$r->send_http_headers();
} else {
$r->status(200);
$r->send_http_headers();
$r->print($data);
}
return Apache::OK;
}
FAIL
sub handler : method {
my ($class, $r) = @_;
if (...) {
$class->not_found($r);
} else {
$class->output_data($r, {
status => 200, # default
body => $data
});
}
return Apache::OK;
}
クラス関係の見直し
とりあえずmod_perlのままデプロイ
FAIL
なぜか404ページが真っ白になる
ErrorDocument
commit 5f9872cbf992777dd8ec8bd67ea38c945f6ebe9c
Author: Daisuke Maki <....@....>
Date: Mon Dec 17 17:47:32 2012 +0900
ErrorDocumentが表示されない現象を修正(or "Why mod_perl must die")
* mod_perlは$r->statusとハンドラの戻り値の関係が非常に複雑で
場合によっては動かない
例:
* $r->status(404) + return OK (or NOT_FOUND)
-> 404レスポンスは正しいがErrorDocumentがトリガーされない
* $r->status(404) + $r->send_http_header + return OK (or NOT_FOUND)
-> 404レスポンスは送信されるが、ヘッダーが2重送信されるので
格好悪いHTTPレスポンスがtext/plainで表示される
というわけでこのあたりを正しく処理する必要がある
…中略…
* そしてmod_perlは死ぬべき
ちなみに
Phase 2: 配信システム→PSGI
POPO = Plain Old Perl Object
Geest
Plack ツール
$perl++
Carton + cpanfile
依存関係
CPANにあがってないモジュール
セットアップ
DEPLOY
PSGIデプロイ テイク1
FAIL
ワーカー数調整
Devel::NYTProf
不要なマウントの削除
Plack::Request (Plack < 1.0018)
URL::Encode
Apacheさんは偉かった
そして
FAIL
svc -hしたら突然LAがあがる
サーバー再起動
carton exec -- \
start_server \
--port 5000 -- \
plackup \
-s Starlet \
--max-workers=80 \
--max-reqs-per-child=500 \
--min-reqs-per-child=350 \
BEFORE
carton exec -- \
start_server \
--port 5000 --signal-on-hup=USR1 -- \
plackup \
-s Starlet \
--max-workers=80 \
--max-reqs-per-child=500 \
--min-reqs-per-child=350 \
--spawn-interval=0.5
AFTER
Slow-restart++
RELAX
Phase 3: Sledgeさん
Sledge::PSGI
Sledgeさんと$r
Sledgeさんと$r
mod_perl
mod_perlの世界へ……
mod_perlさんの世界
mod_perlさんの世界
mod_perlさんの世界
sub post_dispatch_add {
...
# Expects %ENV!!!!
my %cookies = CGI::Cookie->fetch();
...
}
FAIL
%ENV is a _global_, you...
http://www.layoutsparks.com
%ENV参照
%ENV参照
Sledgeさんは以上
Phase 4: さらに先へ
完全停止しないといけない問題
carton exec -- \
start_server \
--port 5000 --signal-on-hup=USR1 -- \
plackup \
-s Starlet \
--max-workers=80 \
--max-reqs-per-child=500 \
--min-reqs-per-child=350 \
--spawn-interval=0.5
aww...
F
FAI
FAIL
(my son nudged me to let him drink my lemonade w/o any sugar)
No babies were harmed during the shoot of this photo
完全停止しないといけない問題
carton exec -- \
start_server \
--port 5000 --signal-on-hup=USR1 -- \
bin/jp2_app
step1
# bin/jp2_app
use LDBlogNG::PSGIRunner;
my $runner = LDBlogNG::PSGIRunner->new(
app => 'LDBlogNG::App::JP2App',
);
$runner->run;
step2
完全停止しないといけない問題
plackupありすぎ問題
$0 = sprintf "%s (%s %s=[%s])",
$0,
$apppath, # etc/app.psgi
$handler_name, # Starlet
join ", ",
map { "$_=$handler_args{$_}" }
keys %handler_args;
# run_psgi (etc/app.psgi Starlet=[max_workers=80 … ])
runner
plackupありすぎ問題
sub handle_psgi {
my ($self, $env) = @_;
…
local $0 = sprintf “%s [%s (%s)] %s”,
Scalar::Util::blessed($self),
$env->{REQUEST_URI},
$env->{HTTP_HOST},
scalar localtime
;
}
# HandlerClass [/foo/bar/baz (blog.livedoor.jp)] Tue Sep 17 10:42:03 2013
app
(俺の)野望
http://codezine.jp/book/modernperl2
(俺の)野望