apacheの最近のブログ記事

子プロセスに処理を渡して、親プロセスで標準出力を切るとき、

my $pid;
if($pid = fork){
 #親の処理
 close (STDOUT);
 wait;
}
elsif(defined $pid){
 close (STDOUT);
 #子の処理
}
 ・
 ・
 ・


みたいな感じで今までOKだったのだが、ロリポップ系サーバなどではこれがうまく行かない。ブラウザの出力自体は切れるのだが、子プロセスの処理を行ってくれない。

WEBサーバによって変わると聞いたことがあるので、ググってみたところ、標準出力を切る部分を、

close (STDOUT);
close (STDERR);
close (STDIN);

とやったら上手く行った。

apache2.0系(うちの環境)とapache1.3系(ロリポップ系?)でどうやら違うらしい。

ちなみに、上記3つの順番が違っても1つ足りなくてもダメだった。

close (STDIN);
close (STDOUT);
close (STDERR);

↑これだとなぜか子プロセスが終了するまでブラウザが開放されない


close (STDOUT);
close (STDERR);
close (STDIN);

↑この順番じゃないとダメみたい。

STDOUTだけだと、新しいapacheのときダメだよって聞いていたので、それとは逆の現象だが、解決したからまあいいか。
----------------------------------------------------------------------------------------------

#!/usr/bin/perl -w

use strict;
use LWP::UserAgent;
use HTTP::Request::Common;

# オブジェクト作成
my $ua = LWP::UserAgent->new();
my $url = 'http://yahoo.co.jp';
my $req = &HTTP::Request::Common::GET($url);

# レスポンスを得る
my $res = $ua->request($req);

# フィールド名を指定してヘッダを取得
my $con_type = $res->header('Content-Type');

#処理
if($con_type =~ /shift_jis/i){
  # (sjis用エンコーディング処理)
}
elsif($con_type =~ /euc-jp/i){
  # (ujis用エンコーディング処理)
}
elsif($con_type =~ /utf-8/i){
  # (utf8用エンコーディング処理)
}
  ・
  ・
  ・

----------------------------------------------------------------------------------------------


※charsetをダイレクトに返してくれるメソッドはどうやら無いらしい・・・
あったら教えてください。
DocumentRoot以外の場所にあるファイルをダウンロードさせようとして、プログラム側で「Location」させても、普通はアクセスできない。

そういった場合は前記事(http://www.igreks.jp/dev/2009/10/perlmysql2.html)の応用で、「cat」コマンドを利用するとダウンロードできるようになる。


-----------------------------------------------------------------------

#!/usr/bin/perl -w

use strict;

my $dir = '../../hoge'; #Documentroot外のディレクトリ
my $file = 'huga'; #その中にあるファイル

print "Content-Type: application/octet-stream\n";
print "Content-Type: application/download; name=$file\n";
print "Content-Disposition: attachment; filename=$file\n";
print "\n";
#### print content
system "cat $dir/$file";

exit;

-----------------------------------------------------------------------


※DocumentRoot以下に置いてBasic認証かけるよりは安全?
※LWP転送するときもOK

実行中のプロセスのCPU使用率やメモリ占有率などをリアルタイムで監視するUNIXコマンド。

-----------------------------------------------------------------

$ su (rootになる)

# top

(プロセス一覧が表示される)


"q"で終了
----------------------------------------------------------------

以上。


オプションとして便利なのは、

-d: 更新間隔を指定する: -d ss.tt (秒.10分の1秒)
-u: 指定した実効UIDかユーザ名にマッチするプロセスだけをモニターする: -u somebody


例えばWEBサーバが実効しているプロセスだけを0.5秒間隔に確認したい場合は、

--------------------------------------------
# top -d 0.5 -u apache
--------------------------------------------

でOK。

perl2exeに四苦八苦

| コメント(0) | トラックバック(0)
かねてから気になっていたperl2exe(perlスクリプトファイルを実行ファイルにしてくれるソフト)についに挑戦。

Win32環境での情報などは結構転がってるのだが、Unix版で参考になるサイトがないので、仕方なく本家のユーザーマニュアルを読みながらやってみる。

まずは本家からダウンロード。
http://www.indigostar.com/perl2exe.htm


私の場合はperl5.10.0でLinux上でコンパイル予定なので、

・Perl2Exe V9.100 for Linux (Jan 18 2008)

↑これを選んでダウンロード&解凍。



なにやらマニュアルを見ると、

・exeファイルの作り方は、コマンドにて、
 「perl2exe yourscript.pl」
とするだけ。ふむふむ。

・特別なモジュールを読み込む場合は、スクリプト中に
  #perl2exe_include "somemodule.pm";
的なことを書けばよいと・・・

まあこの辺はWin32版と同じだな。


ほんでもって、Unixホストで動かす場合は、同梱されてるインタプリタじゃなくて、動かしてるサーバのインタプリタとコア/ローカルモジュールを使用する設定にできるらしい。

後々、こっちの方が楽そうなので、切り替えてみる。

--------------------------------------------------------------------
cd ~/perl2exe
rm -rf perl5
perl ./setup_perl2exe.pl
--------------------------------------------------------------------

「切り替えました!」的なことが表示されたので、多分OK。



とりあえず試しに使ってみる。

まず最初に、
--------------------------------------------------------------------
cd ~/perl2exe
./setup
--------------------------------------------------------------------


実行ファイル生成
--------------------------------------------------------------------
cd ~/perl2exe
./perl2exe hellocgi.pl
--------------------------------------------------------------------


同じディレクトリに「hellocgi」という実行ファイル(バイナリファイル)ができた!!


とりあえず動作確認。
--------------------------------------------------------------------
cd ~/perl2exe
./hellocgi
--------------------------------------------------------------------
(あくまで実行ファイルなのでファイル名を指定するだけ)

・・・・よっしゃ成功!!



次に、WEBサーバ(ブラウザ)から実行できるか実験。

マニュアルにはtelnetを使って・・・みたいなこと書いてあったけど、面倒くさいんで、

#!/usr/bin/perl -w

system "./hellocgi";

exit;

とだけ書いたperlスクリプトを実行ファイルと同じ場所に置いて、このファイルにアクセスする。


よしよし、ちゃんと表示される。html出力もOKですな♪




じゃあいよいよ、もっと複雑なDBが絡んだスクリプトに挑戦してみようってことで、やってみたのだが、もちろん一発でうまくいくわけがなく、以下のエラーが連発。

Warning: Can't locate VMS/Stdio.pm
at /usr/lib/perl5/5.10.0/File/Temp.pm line 149
@INC = /usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi, /usr/local/lib/perl5/site_perl/5.10.0, /usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/vendor_perl/5.10.0, /usr/lib/perl5/vendor_perl, /usr/lib/perl5/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/5.10.0, ., .

Warning: Can't locate Compress/Bzip2.pm
at /usr/local/lib/perl5/site_perl/5.10.0/HTTP/Message.pm line 315
@INC = /usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi, /usr/local/lib/perl5/site_perl/5.10.0, /usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/vendor_perl/5.10.0, /usr/lib/perl5/vendor_perl, /usr/lib/perl5/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/5.10.0, ., .

Warning: Can't locate Compress/Bzip2.pm
at /usr/local/lib/perl5/site_perl/5.10.0/HTTP/Message.pm line 447
@INC = /usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi, /usr/local/lib/perl5/site_perl/5.10.0, /usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/vendor_perl/5.10.0, /usr/lib/perl5/vendor_perl, /usr/lib/perl5/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/5.10.0, ., .

Warning: Can't locate Compress/Bzip2.pm
at /usr/local/lib/perl5/site_perl/5.10.0/HTTP/Message.pm line 496
@INC = /usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi, /usr/local/lib/perl5/site_perl/5.10.0, /usr/lib/perl5/vendor_perl/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/vendor_perl/5.10.0, /usr/lib/perl5/vendor_perl, /usr/lib/perl5/5.10.0/i386-linux-thread-multi, /usr/lib/perl5/5.10.0, ., .


(以下省略)



チーン。

まあ、エラーの言ってる意味はわかるのだが、Compress/Bzip2とか、聞いたこと無いようなモジュールまで要求してきやがる。

どうやら動作条件に関係なく、モジュール中にuseとかrequireとかの命令があったら、evalで呼ばれてても、とにかくそのモジュールはロードしなきゃならん仕様らしい。


仕方ないからインストールしてやるかと思い、cpan2rpm使おうとしたら「見つかりません!」的な。

ここまできたら、全部入れてやればいいんだろと思い、全部cpanからダウンロードしてきてmake installを実施。

しかしインストール中に今度は、

/bin/sh: gcc: command not found......

Cコンパイラまで追加すんのかよ!と思いつつ、こちらのサイト
http://memorva.jp/memo/linux/gcc_curses.php
を参考にしつつ、gccをインストール。

--------------------------------------------------------
yum install gcc*
--------------------------------------------------------

まあyumで一発だからいいけど。


これでようやく要求された全てのモジュールのmake install が完了。

インストール中に何やらいっぱい警告だのエラーだの表示されたけど、とりあえずpmファイルが入ったからいいや的な。


そしてもう一度実行ファイルを生成!

・・・お?

今度はエラーが出ない。

イエーイ!コンパイル成功〜〜〜〜!

さっそく実行〜!


あれ?

Software error:

DynaLoader object version 1.0801 does not match $DynaLoader::VERSION 1.08 at PERL2EXE_STORAGE/DynaLoader.pm line 93.
Compilation failed in require at PERL2EXE_STORAGE/DBI.pm line 157.
BEGIN failed--compilation aborted at PERL2EXE_STORAGE/DBI.pm line 157.
Compilation failed in require at ** line 15.
BEGIN failed--compilation aborted at ** line 15.


・・・うーむ・・

どうやらDBIの設定がいろいろ必要らしい。


苦戦は続く・・・



そして改めて説明をよく見ると、「Mysqlを使用する場合は、DBD::Mysql_PPを使用してください」
みたいなことが書かれている・・・

ということは、通常のCを使うデータベースドライバが使えないっつーことか。

このあたりで、ひょっとすると、これはものすごく使えないソフトなのでは・・・という不安がよぎる。


調べてみると案の定、Mysql_PPはいつまでたってもバージョンが0代だし、処理がくそ遅いという評判。


まあ全てPurePerlでやろうってんだからそうなるだろうな。

さらにMysql_PPの依存モジュールであるNet::Mysqlモジュールでもようわからんエラーが続出。




そして、ついに対応するのをあきらめた私。



結論:

データベース連携するプログラムはPerl2exeで(気軽に)使えない。
そうじゃないものなら使用する価値はまあまあある。
ただしスクリプトにモジュール名が書いてあったら必ず必要。


以上、ご参考までに。
ブラウザからのデバック中とかに、うっかり無限ループさせてCPUがフル回転に
なっちゃったときとか、Fedoraのシステムモニタ(Windowsでいう
タスクマネージャ?)で止めたいプロセスIDを探したくても、apacheユーザーで
動かしたプロセスは、1ユーザーでログインしてる場合は表示されない。
(rootでログインしないと表示されない)

そんなとき、てっとりばやく騒音をおさえたいのでメモ。


コマンドラインからSUになり、

--------------------------------------------------------
#top
--------------------------------------------------------

コマンドを実行すると、実行中のプロセスIDなどがCPU負荷の高い順に表示されるので、
停止させたいプロセスIDを見つけて、

--------------------------------------------------------
#kill -9 プロセスID
--------------------------------------------------------


これが一番早いかな。

自分がapacheのグループに入ってればシステムモニタで確認できるのかな?
まだ試してないけど。
最近yumのパッケージなどあまり更新してなかったので、久々にやるかと思って、
GUIでアップデートを行なったらいきなりperlスクリプトが500Internal Server Error。

うざーー!

最初にCGI::Carp qw(fatalsToBrowser)を呼んでいるので、このエラーの場合は
たいていヘッダー出力が間違っていることがほとんど。

しかしどこもおかしくない。

/var/log/httpd/error_log を見ても、お得意の
「Premature end of script headers」

しかしよーく見ると
「Can't locate object method "splitpath" via package "File::Spec" at /usr/lib/perl5/5.10.0/CGI/Carp.pm line 361, line 64.」

なので、試しに、同じようにCarp.pmを使用してるMTのスクリプトにアクセスしてみたら、同様のエラーコメント。


今回のyumアップデート直後のエラーだけに
/var/log/yum.log を見てみる。

Apr 25 16:01:29 Updated: httpd-2.2.11-2.fc10.i386
Apr 25 16:01:29 Updated: 4:perl-libs-5.10.0-68.fc10.i386
  ・
  ・
Apr 25 16:02:37 Updated: cpan2rpm-2.028-6.fc10.noarch

うーん、なんかこの辺が怪しい感じ。


アパッチのアップデートも入ってるけど、perlのモジュールを結構全面的に
書き換えてる感じだから、とりあえずエラーが出てるおおもとの
File::Specモジュールをとりあえずインストールしなおすかってことで・・

たしかこれはCpanのRPMパッケージだったはずだから、とりあえず、

----------------------------------------------------
# rpm -e perl-File-Spec

# rpm -q perl-File-Spec
パッケージ perl-File-Spec はインストールされていません。

----------------------------------------------------


と、ここで何となくスクリプトを実行してみたら、
あれ・・・動いた・・・。

MTにもちゃんとログインできる・・・


/usr/lib/perl5/ の中を確認すると、何か知らんけどFile::Specモジュールが
入ってる・・・
ということは、今回のアップデートでperl5.10.0の標準モジュールになった
ってこと?
いやいやそんなはずはない。Carp.pmなんてずっと昔から使ってるんだから。

rpmを削除してスクリプトがちゃんと動くってことは、今まで標準
モジュールよりRPMパッケージの方を優先して読み込んでたってこと?

てゆうか、最初からFile::Spec入ってるのになんで俺RPMでインストールしちゃって
るんだろう?

とにかく今回のモジュールアップデートでどこかダブったんだか改行コードがおかしく
なったんだかようわからんが、直ってよかった。

2日ハマったのでメモ。
WEBブラウザで処理時間の長いCGIなんかを実行したとき、apacheのTimeOutの設定によっては最後までスクリプトが実行されないで終わってしまうのは言うまでもない。

レンサバなどでこういった時間のかかるスクリプトをcron起動させているユーザは、cronの結果がメールで届くまでは、ブラウザからしか実行の完了確認ができないのでは?と、ふと思った。

ローカル環境でない場合、httpdの接続タイムアウトが例えば120秒に設定されていて、起動させるスクリプトが終了するまでに180秒かかるものだったら、WEB上ではタイムアウトになってしまうためユーザはほんとうに最後までちゃんと実行されているのか非常に不安になるはずだ。

特にある程度の量のメール送信機能が組み込まれたスクリプトだと、相手にちゃんと届いているのかすぐに判断できない。
しかも知らないうちにサーバ管理者がCGIの実行時間の制限なんかしていたらもっと都合が悪い。

まあ、結局cron実行結果のメールを見れば分かるのだが、なんか効率悪いので、わかりやすいようなかたちで検証してみた。


まず/etc/httpd/conf/httpd.conf の設定で、ブラウザの接続タイムアウト時間を一時的に10秒に変更。


TimeOut : 120
   ↓
TimeOut : 10

httpdを再起動する。


次に、「timeout.cgi」とか名前を付けたファイルを任意の場所(ここでは/var/www)に作成し、以下のように記述。

------------------------------------------

#!/usr/bin/perl

print "60秒sleep start...\n";
sleep 60;   #60秒待つ
print "60秒経過しました。sleep end.\n";
print "apacheのタイムアウトは10秒ですが、スクリプトは最後まで実行されました。\n";
exit;

----------------------------------------------

このファイルを実行権限を付加して保存。



コマンドラインからこのファイルを実行。

# cd /var/www
# perl timeout.cgi


【結果】

60秒sleep start...
(60秒間カーソル点滅)
60秒経過しました。sleep end.
apacheのタイムアウトは10秒ですが、スクリプトは最後まで実行されました。




・・・というわけで、
レンサバでcron動かしてる人たちは、ローカルできちんと動作確認できていれば、crontabの書き方が間違ってない限りちゃんとスクリプトは最後まで動きますよ!

・・・ということがわかってもらえたと思う。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちapacheカテゴリに属しているものが含まれています。

次のカテゴリはHTMLです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

Powered by Movable Type 4.22-ja