日常の最近のブログ記事

ちょっと案件で簡単なCGIスクリプトをを開発することになった。StarmanとかTwiggyでほとんど全て書いているのに今更CGIとかそういう突っ込みはとりあえずおいておいて・・・環境を作るのも面倒くさいし、簡単にサーバーを立ち上げたり落としたりしたい。

そこでPlackです!

追記:その後もらったコメントによると、こちらのほうがよさそうです







具体的にはplackupとCGI::Emulate::PSGIを使います。

何も考えずにとりあえず開発したいので、以下のようにapp.psgiにコードを書いていく。
use strict;
use CGI::Emulate::PSGI;
return CGI::Emulate::PSGI->handler(sub {
    CGI::initialize_globals(); # 重要
# ここから
#!/usr/bin/env perl
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);

sub main {
    my $q = CGI->new();
    ....
}

main();

# ここまでがCGIのコード
});
あとで本当に単純にコピペしたいのでshebangもそのまま書いちゃうし、インデントもその部分だけファイルに書いたかのように記述していっちゃいます。

これを以下のように-rオプションをつけて起動。app.psgiのCGIコードに変更を加える度にサーバーも再起動して新しいコードを適用してくれる。
plackup -r -a app.psgi


これはいいわー。
100305_2046~02.jpg
Yokohama Perl Mongersのみんなが関内に向かう途中で電車が止まって右往左往している間、僕は昨年 LLTVに出させてもらった縁からアスキーメディアワークスさんでPerlの権益のために声を張ろうと思ってLLふんふん2010のブレストに行ってきましたよ。

結果的には声を張るような状況ではなく、ドミノピザと景品で当てたというブラッセルズのケグからビールをぐびぐび飲みながら壁にペタペタとネタを貼っていくという2時間でありました。最後の片付けはバスの時間あやばかったのでバックれました。すみません。

というわけで今年は7/31に虎ノ門のニッショーホールで開催だそうです。内容はまだ未定。今回のブレスト内でのネタがどれだけ反映されるのでしょうね。

YAPCは多分10月ですよ(ぼそ)
Perlを使うことのできる中小企業(地方企業含む)って結構いると思うんだけど、そういうのをとりまとめたリストを作って公表するとか、もしくは弊社(endeworks)と取引のあるところと今後の仕事の際にそういう会社に仕事を流して関係を築いていくとか、そういうのって需要あるのかなぁ?

発注したい側、受注したい側、両方とも意見が聞けると嬉しい。

追記1: 見切り発車でこんなwikiページも作ってみました。よろしかったら書き込んでください!

追記2: リンク先間違ってました!直しました!
「だからどうだ」ってことですけど、(perlだとreverseあるので本来なら1オペで終わっちゃうけど)とりあえずループを使わずに与えた配列を逆にするコードの自己最短コードはこうなりました:

sub r{@_?(pop,r(@_)):()};
もう少し読みやすく展開するとこんな感じですね。ただの再帰処理です:

sub myreverse {
   if (@_ > 0) {
      return (pop @_, myreverse(@_));
   } else {
      return ();
   }
}
popで配列の最後の要素を最初に回して、残りを再帰処理してるだけー
今日家に帰ってきたら相方は豚キムチを作ってたのだけど、横でお手伝いにジャガイモをむきがてらそのキムチをつまんでみたところ・・・うまい!うまいじゃないか!スーパーで買ってきたキムチにしては格段にうまいぞ、これ!

本場のキムチに関して特にうんちくは持ってないので比べてみてどうなのかはわからんけど、この「王道キムチ」っていう商品は浅漬けでしっかり辛くて甘みもあり、俺の好みにバッチリ。思わず残ってたものを全部食ってしまい、その後ネットを調べたら検索にヒットする結果がかなりべた褒めしているではないか。みんなも好きなんだね!

というわけで王道キムチ、オススメです。
モヤモヤさまぁ〜ず2のDVD 7, 8, 9を予約購入。大江アナが相変わらず美しいので、見ながらそう呟いていると横の相方からつめた〜〜〜〜〜い一言が飛んでくるのだが、こればっかりは辞めるつもりはないのであった。我慢せよ。

ところで今回のDVDの予約購入特典として「雨の幡ヶ谷」エピソードとかが*抽選で*あたるらしいんだけど・・・なんで?なんでいれてくれないの?!意味がわかりません!

テレビシリーズもののDVDでこうしてエピソードが削られたりするのが本当に嫌なんですけど、なんとかならないですかね。諸事情で出せないエピソードがたまにあるのはまぁしょうがないけど、しれーっと削られてるのはわざわざ金を出して買ってる身としてはかなり遺憾ですね。ちなみに特にひどいと感じたのは「内村プロデュース」編集しすぎじゃ!。あと、「くりぃむナントカ]」シリーズも妙に混ぜないで全部出して下さいよ・・・。

こんどゴールデンに行くみたいだけど、今まで通りのテイストでちゃんとやってくれるのかなぁ。フォーマット変えられたら、すぐ見るの辞めるとおもうので、そこのところ是非がんばってください>伊藤P

ちなみに特典のテレ東モヤモヤは結構楽しめました。
本日携帯を忘れていますので、携帯へ連絡しても見られません :(

連絡はtwitterかdaisuke@弊社まで。
某出版社さんに打ち合わせに行ってきたのだけど、このように自分が普段触れない業界の方と話してると必ず思い出す話がある。それはdaibaさんに紹介してもらったこれ→「ムダと一緒に捨てたもの」。

問屋というシステムと現代のムダを削る話なのだが、まぁ現在の状況がいいとか悪いとかは自分で調べてもないのでとりあえずざっと斜め読みしてもらって、キモは2ページ目の「問屋の裏機能」あたりから「そのせいで技術も低下する」のあたり。

出版社の方と話している限り僕は「(物を作るという意味での)作家」側にいるわけだが、話している際に市場のニーズの事や、現実的な流通の経路やビジネスモデルなんかの話をしてもらってそれに合わせて内容を調節していくという事をしていると作家としての「こういうものを書きたい」と思ってる自分とは別に事情とかを聞いて「なるほど」と思っている冷静な自分が同時に考えている。そして毎回非常にそのやりとりとそれをしている事自体がおもしろい。

そういうわけで、話終わった後「彼らはいい『問屋さん』だよなぁ」と思っていつも帰路につく。これで彼らがいなかったらきっとただの垂れ流ししか作れてないと思うのだ。

ネットの時代は様々なコンテンツに関して制限がなくなって、大変素晴らしい事もたくさんあるんだけど、やはり問屋というもの自体は必要だと感じる。要はその二つがちゃんと両立できればいいんじゃないかな。「ムダがある」と分かっていても、市場のニーズや目利きをちゃんとできる問屋方式と、そこに選ばれなかったけど隠れた才能やニーズが本当はあった場合に使える作家→消費者の直接取引と、両方。もうインターネットを含む情報の氾濫の時代は終わらないと思うから、逆に守るべきは問屋方式なんじゃないかなぁ。

かく言う自分も本当はできればプログラマー・デザイナーの問屋方式に近い形で仕事できたらいいなぁと思ってる。そういえば今月の始めでendeworksも5年目でした。会社は10年もってやっと一人前らしいのであと6年くらい。まだ折り返し地点に到達してないんだなぁ。普段コードの事ばかり書いてるけどデザイン業務とか色々できるので是非一度声をかけてみてくださいね!


  • 注1:まだ本番にはデプロイしてませんが、確認テストでは使いました(単位テストでは使わない。あくまで本番さながらの形で動いているのを確認したい時だけ)。
  • 注2:以下スクリプトは開発者の労力を減らすためのスクリプトで、万全なデプロイ方法だとか言うわけではありません。
  • 注3:正直シェルスクリプトは素人です。

  • 追記:envdirはどうか、と言われた件。最初それを思い出せなくてcat ENVなんてしてたんだけど、設定値をもらって後からフックしたいところがあるからenvdirではそれを実現できない・・・気がする。ので、今回は以下で。
  • hirose31 さんが美しい スクリプトを提供してくれたので、それをベースにしてgithubにあげておけました。最新版はここです

ここ最近のPlackだとかStarmanとかを使ったWebアプリケーションのバンドル・デプロイについてちょっと固まりつつあるので、書いてみる

まず アプリケーションと、その依存関係。デプロイ側のサーバーにはlocal::libと必要なModule::Install系のモジュール、それにModule::Install::Bundle::LocalLibがインストールされている前提です。アプリケーションの依存関係は全部Makefile.PLに書きます。

use inc::Module::Install;

name 'MyApp';

..... # 必要な事色々 ....

# Plack stuff
requires 'Plack' => '0.9910'; # or 1.00 when the time comes
requires 'Starman';
requires 'Server::Starter';
requires 'Net::Server::SS::PreFork';

bundle_local_lib;

WriteAll;

こんな風にしておく。で、デプロイする際には
make bundle_local_lib
する。するとextlibというディレクトリに依存関係が全部入ります。このextlibは一旦安定稼働するのを確認したら、依存関係のアップグレード時には一旦別のところに待避させるとかコピーするとかしてからアップグレードを行ってみるという事ができる。万が一動かない場合はすぐ元のextlibに戻せば良いってわけだ。

ってなわけで、Plackを含めた全ての依存関係をextlib以下にある。

で、これをdaemontoolsで動かすのでrunファイルが欲しい。作る。今までdaemontoolsで運用してて開発→デプロイで面倒くさいなーと思ってたのがこのrunファイルの細かい設定を変えていくことなんだけど、今回はこれを分離してみた:
#!/bin/sh

# ENVというファイルが このファイルと同じディレクトリか
# pwdにあれば、それを読み込んで、そこから環境変数を広う。
# 例えば後で出てくる PSGI_FILEの場所を明示的に指定したければ
# PSGI_FILE=/path/to/app.psgi とかENVファイルに書いておく。
if [ -f `dirname $0`/ENV ]; then
    ENV_FILE=`dirname $0`/ENV
    export `cat $ENV_FILE`
elif [ -f ENV ]; then
    export `cat ENV`
fi

if [ -z $APP_HOME ]; then
    APP_HOME=`pwd`;
fi
export APP_HOME
if [ -z $CATALYST_HOME ]; then
    CATALYST_HOME=$APP_HOME
    export CATALYST_HOME
fi

if [ -z $CATALYST_CONFIG ]; then
    if [ -f "catalyst.yaml" ]; then
        CATALYST_CONFIG=catalyst.yaml
        export CATALYST_CONFIG
    fi
fi

if [ ! -z $DEBUG ]; then
    DBIC_TRACE=2
    export DBIC_TRACE
fi

if [ -z $PLACK_SERVER ]; then
    PLACK_SERVER=Starman
fi

if [ -z $PSGI_FILE ]; then
    PSGI_FILE=app.psgi
fi

if [ -z $PORT ]; then
    PORT=5000
fi

if [ -z $USER ]; then
    USER=www
fi

if [ -z $PERL ]; then
    PERL=`which perl`
fi

EXTLIB=$APP_HOME/extlib

# start_serverを通して plackupを実行するのだが、こいつらはextlibの中に
# あるので、それを指定して実行する(local::lib設定もつけないと依存関係が
# みつからない状態になってしまう)
exec setuidgid $USER \
    $PERL -Mlocal::lib=$EXTLIB \
    $EXTLIB/bin/start_server --port $PORT -- \
    $PERL -Mlocal::lib=$EXTLIB \
    $EXTLIB/bin/plackup -s $PLACK_SERVER -a $PSGI_FILE -p $PORT 2>&1

こんな感じ。これでENVの中身を変えてsvc -tするとその設定が反映される、と。

自分の場合はPSGIファイルの中にももう少し仕掛けを入れていく必要があったので、ENVから可変な情報をもらっていくようにした:
use strict;
use lib "$ENV{CATALYST_HOME}/lib"; # パスを通す
use local::lib "$ENV{CATALYST_HOME}/extlib"; # ついでにlocal::libのパスも通す

use MyApp;
use Plack::Builder;

MyApp->setup_engine('PSGI');

builder {
    # リバースプロキシ使う場合はenableしちゃう
    if ($ENV{USE_PROXY}) {
        enable "Plack::Middleware::ReverseProxy";
    }
    return sub { MyApp->run(@_) };
};
これをレポジトリに入れておき、デプロイするときにはdaemontoolsあたりからsymlinkしておいて動かす。開発時にもrunファイルを実行すれば本番さながらの感じでサーバーが立ち上がる(ただし、実際にはテストは全然違う方法で動かしてる)

誰かの役に立つなら幸い。なんか突っ込みがあればお願いします。
ちょっとずれてるので横からコメント

unshift、push で変更を加えた @INC(モジュール検索PATH)が使用されない
起こってる現象とこの認識はちょっと違う。

具体的に何が起こっているか説明する前に、Perlにはコンパイル(BEGIN) フェーズとランタイムフェーズという、2回コードが実行されるタイミングがある(まぁ厳密にはもう少し色々フックすることが可能だけど、とりあえず一般的にはその二つで大丈夫)。

これがどういうことかというと、順番にコードを書いているつもりでもコンパイルフェーズで評価される部分とランタイムフェーズで評価される部分があるということ。わかりやすい例としてはこんな感じか:

#!/usr/bin/perl
use strict;
print "Runtime!\n";

BEGIN {
    print "Compile time!\n";
}

BEGINで囲まれた部分はコンパイルフェーズで実行され、BEGINの前にあるprint文より前に実行されるはず。

で、一般的にモジュールを読み込む"use"宣言はどうかというと、これはコンパイルフェーズで実行される。"use"宣言というのは実は以下の構文と同等なのだ:
# use MyClass;
BEGIN {
    require MyClass;
    MyClass->import;
}

つまり、use宣言で扱うクラス名が発見されるためには、コンパイルフェーズ時に@INCが変更されてなくてはならない。mod_perlだろうとなんだろうとこれは一緒なので、mod_perlじゃなくても以下のコードではMyClassは見つからない:
unshift @INC, "/path/to/MyClass";
use MyClass;
つまり、"/path/to/MyClass"をuse宣言に認識させるためには以下のようにする必要がある:
BEGIN {
    unshift @INC, "/path/to/MyClass";
}
use MyClass;
これなら、どちらもコンパイルフェーズで動き、あとは読み込まれた順番に処理されるから問題無し!

まぁでもmod_perlを使うのなら、なにか制限がない限りstartup.plで@INCを普通にunshift/pushで変更しておくのが一番いいと思う。

筆者

daisuke - Perl hacker, endeworks 代表取締役, Japan Perl Association 代表理事

このアーカイブについて

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

前のカテゴリは旅行です。

次のカテゴリはです。

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

Powered by Movable Type 4.1