結論から言うと、親プロセスの「wait;」の直後にもう一度MySQL接続処理を呼ぶ。
※2010/7/23追記:さらに各プロセスの頭でMySQL接続処理を呼ぶ。
ただそれだけ。
■MySQL接続用(db.pl)
--------------------------------------------------------------------------
package db;
use strict;
sub open{
my $dbs = "DBI:mysql:$dbname:$dbhost";
our $dbh = DBI->connect($dbs,$dbuser,$dbpass);
if(!$dbh){ die 'MySQL connection error!'; }
}
sub query{
my ($sql) = @_;
our $sth = $db::dbh->prepare($sql) || die $db::dbh->errstr();
my $exec = $sth->execute() || die $sth->errstr();
return $exec;
}
sub close{
$db::sth->finish();
$db::dbh->disconnect();
}
1;
--------------------------------------------------------------------------
■よくあるforkの処理
--------------------------------------------------------------------------
#!/usr/bin/perl
use strict;
use DBI;
require 'db.pl'; ######## 上のファイル読み込み
&db::open(); ######### 最初のMySQL接続
(親プロセス処理)
my $pid;
FORK: {
if($pid = fork) {
&db::open(); ###### ←【ここで単発接続】
(親プロセス処理)
close(STDOUT);
wait;
&db::open(); ###### ←【ここで再接続】これはfork終了後の処理用
}
elsif (defined $pid) {
&db::open(); ###### ←【ここで単発接続】
close(STDOUT);
(子プロセス処理)
exitしなくても勝手にexitされる?
}
elsif($! =~ /No more process/){
sleep 5;
redo FORK;
}
else{
die 'Fork is not supported!';
}
} # End Of Label:FORK
(親プロセス処理再開)
&db::close(); ######### 正規のMySQL接続切断
exit;
--------------------------------------------------------------------------
今まで、子プロセス内処理が終われば、全体の処理も終わるような構造のスクリプトばっかりだったので、なかなか気づかなかった。
ログも「mysql server has gone away...」ってしか出ないし。
標準出力を切ってるからブラウザからのデバックだけだと気がつかず、メルマガの空メール処理実装しようとして初めて気がついた。
一般的には、子プロセス内に入ったら、改めて子プロセス専用のコネクションを作らないと、子プロセスの終了時にMySQLコネクションが切断されてしまうらしい。
(つまり、親と同じコネクションを使っていると、親のコネクションも切れる)
全然しらんかった。
でも、なぜか子プロセスの最初で「&db::open();」してもダメだった。
perlのforkは親の変数が子に全部コピーされるから(同じデータベースハンドル、またはステートメントハンドルを使っている)なのかな?
わざわざ、子プロセス専用のSQL発行サブルーチン作るのも非効率だし、どうしようかなと悩んだ挙句こうなった。
時々、MilkyStepで即時配信メールが送れなくなるのはコレのせいだったりして。
※2010/7/23追記:
子プロセスの処理中に親プロセスが終了しても、子プロセスのMySQL接続が切れる。
また、親が終了する前に子のプロセスIDを使い始めると親のMySQL接続が切れる。
原因はよくわからんが、親・子それぞれの頭で接続処理を単発で入れたら上手く行った。
※2010/7/23追記:さらに各プロセスの頭でMySQL接続処理を呼ぶ。
ただそれだけ。
■MySQL接続用(db.pl)
--------------------------------------------------------------------------
package db;
use strict;
sub open{
my $dbs = "DBI:mysql:$dbname:$dbhost";
our $dbh = DBI->connect($dbs,$dbuser,$dbpass);
if(!$dbh){ die 'MySQL connection error!'; }
}
sub query{
my ($sql) = @_;
our $sth = $db::dbh->prepare($sql) || die $db::dbh->errstr();
my $exec = $sth->execute() || die $sth->errstr();
return $exec;
}
sub close{
$db::sth->finish();
$db::dbh->disconnect();
}
1;
--------------------------------------------------------------------------
■よくあるforkの処理
--------------------------------------------------------------------------
#!/usr/bin/perl
use strict;
use DBI;
require 'db.pl'; ######## 上のファイル読み込み
&db::open(); ######### 最初のMySQL接続
(親プロセス処理)
my $pid;
FORK: {
if($pid = fork) {
&db::open(); ###### ←【ここで単発接続】
(親プロセス処理)
close(STDOUT);
wait;
&db::open(); ###### ←【ここで再接続】これはfork終了後の処理用
}
elsif (defined $pid) {
&db::open(); ###### ←【ここで単発接続】
close(STDOUT);
(子プロセス処理)
exitしなくても勝手にexitされる?
}
elsif($! =~ /No more process/){
sleep 5;
redo FORK;
}
else{
die 'Fork is not supported!';
}
} # End Of Label:FORK
(親プロセス処理再開)
&db::close(); ######### 正規のMySQL接続切断
exit;
--------------------------------------------------------------------------
今まで、子プロセス内処理が終われば、全体の処理も終わるような構造のスクリプトばっかりだったので、なかなか気づかなかった。
ログも「mysql server has gone away...」ってしか出ないし。
標準出力を切ってるからブラウザからのデバックだけだと気がつかず、メルマガの空メール処理実装しようとして初めて気がついた。
一般的には、子プロセス内に入ったら、改めて子プロセス専用のコネクションを作らないと、子プロセスの終了時にMySQLコネクションが切断されてしまうらしい。
(つまり、親と同じコネクションを使っていると、親のコネクションも切れる)
全然しらんかった。
でも、なぜか子プロセスの最初で「&db::open();」してもダメだった。
perlのforkは親の変数が子に全部コピーされるから(同じデータベースハンドル、またはステートメントハンドルを使っている)なのかな?
わざわざ、子プロセス専用のSQL発行サブルーチン作るのも非効率だし、どうしようかなと悩んだ挙句こうなった。
時々、MilkyStepで即時配信メールが送れなくなるのはコレのせいだったりして。
※2010/7/23追記:
子プロセスの処理中に親プロセスが終了しても、子プロセスのMySQL接続が切れる。
また、親が終了する前に子のプロセスIDを使い始めると親のMySQL接続が切れる。
原因はよくわからんが、親・子それぞれの頭で接続処理を単発で入れたら上手く行った。

コメントする