時計を壊せ

駆け出しWebプログラマーの雑記

Job-Queue Workerの実装を管理するdaemon

Message Queueとか

だいたいみんな、Message QueueとしてGearmanとかQ4MとかResqueとかRabbitMQとかZeroMQとかまあたくさんあるけど、なにかを使っていると思う。 Perlの人だとQudoとかTheSchwartzとかをつかっている人も多いと思う。
でも、preforkなworkerを実装するとなるとSignal処理とかをちゃんとやるのが意外と難しい。 下の2つのスライドを読むと難しいんだなぁという事がなんとなくわかるとおもう。

graceful shutdownとかgraceful restartとかは欲しいし、max_reqs_per_child的なこともしたいし、時間が掛かり過ぎているjobはリトライして新しいworkerで処理させたいとかそういう要求がある。
そこで、そのへんが共通化されたプロダクトがあると良いのではないかと考えた。

Dainamoについて

なお、perlにおいては似ている既成のプロジェクトとしてDainamoというものがある。*1

これは以下のような事ができて、以下のようなメリットがある。 * Message Queueの種類をあまり考慮せずにコードが書ける * サーバー毎にworker数を設定し、Profileという単位でweightをかけてworker数をバランスする * サーバー毎のプロセス数をスペックに合わせて管理しやすい * Profileを1つのプロジェクトで複数つくって即処理したいものはweightを多めにするといったこともできる * 設定ファイルからProfile::Group(Profileをまとめたもの)を複数読み込み、全てのworkerを起動できる * 複数プロジェクトが同居するケースとかのセットアップが楽

これは業務で運用しているが、とても便利な反面、困ったこともいくつかでてきた。

  • dainamo毎にworker数を設定し、Profileという単位でweightをかけてworker数をバランスする
    • 実際にProfileに割り当てられるプロセス数が分かりにくい。
    • 他のProfileの影響を受けてProfileのworker数が変化するので複数Projectの同居などを慎重に検討しなければならない。
  • graceful_shutdown_timeout(default:10秒)を超えるとSIGKILLをworkerプロセスに送る
    • 容赦が無さすぎて失敗時に走らせたい処理とかが出来ない
  • Proc::Daemonでdaemonizeする機能がある
  • 3段階のforkとなっていてデバッグし辛い
    • master process -> manager process (profile毎に1つ) -> worker process (実際のjobを捌く)
    • (依存モジュールが古いサーバーとかだと)manager processだけゾンビってるとかが稀にある

Workmanについて

というわけで、もっとシンプルなものが欲しいと思っていた。そこで最近、Workman というプロジェクトを開始した。 Job-Queue Worker frameworkと銘打っている。だいたい以下のような事が出来る事を目標にしている。

あらゆるMessage Queueを同一のインターフェースで扱う事が出来る

  • 時代の変化で古いMessage Queueから新しいMessage Queueに移行するときとかにあまりめんどくさい事考えたくない。
  • 代わりに、一部のMessage Queueに特有の機能は使いにくくなるがそれは許容する。
  • Queueバインディングの仕様を満たすためのテストを提供してQueueバインディングを開発しやすくする。

単一のProfileに対して単一のServerを立てる

  • (dainamoと比較して)manager process単位でサーバーを立てる。
  • 複数建てたければ建てればいい

上に挙げた2つのスライドのノウハウを取り入れる

  • シグナルハンドリングの不具合とかを心配したくない。

graceful shutdown / graceful shutdown をサポートする

  • 1つだけ時間がかかっているjobがあったとしても他のworkerはすぐrestartして欲しい
  • かといっていつまでも死なないのも困るのでgraceful_shutdown_timeoutを超えたら強制終了させる

graceful_shutdown_timeoutを過ぎて強制終了させるときにSIGABRTを送る

  • worker内ではWorkman::Server::Exception::ForceKilledがthrowされるのでそれを好きにゴニョる
  • on_abortというhookがあるので再enqueueなどの処理を書いてあげる

max_reqs_per_childしてくれる

  • あたりまえのようにサポートしてほしい

daemonizeをサポートしない

テストを充実させる

  • 特にシグナル処理の安全性やWorkerのライフサイクルとかは手動で動作確認とか結構厳しいし自動化するべきである

CodeRefを簡単にworkerにしたい

  • ちょっとしたプロジェクトとかだとあると便利なはず。Amon2::Lite的な発想。syntax sugar用意してもいいかも。
  • 当然classとしてもタスクを定義出来るようにする。

実装状況

実は、だいたいコア部分はできている。 たまにテストがコケる事はあるが、sleepとか絡むので仕方ないのかなともおもう。 以下のような感じで書くともうだいたい動く。

サーバー側

use strict;
use warnings;
use utf8;

use Data::Dumper;
use Workman::Server;
use Workman::Server::Profile;
use Workman::Queue::Gearman;
use Workman::Task;

my $queue   = Workman::Queue::Gearman->new(job_servers => ['127.0.0.1:7003']);
my $profile = Workman::Server::Profile->new(max_workers => 10, queue => $queue);
$profile->set_task_loader(sub {
    my $set = shift;

    warn "[$$] register tasks...";
    $set->add(
        Workman::Task->new(Echo => sub {
            my $args = shift;
            warn Dumper $args;
            return $args;
        })
    );
    $set->add(
        Workman::Task->new(Abort => sub {
            my $args = shift;
            die Dumper $args;
            return;
        })
    );
    $set->add(
        Workman::Task->new(Busy => sub {
            my $args = shift;
            sleep 1 for 1..1000;
            return;
        })
    );
});

Workman::Server->new(profile => $profile)->run();

set_task_loaderはWorkerプロセスで実行されるのがミソ。
この中でモジュールのロードを行えばgraceful restartしたときでもTaskが再読み込みできるし、 メモリを節約したいなら先に読んでおいてCoWを効かせてメモリを節約することもできる。 重いモジュールは先に読ませておくとかそういう小手先の諸々ができる。

クライアント側

use strict;
use warnings;
use utf8;

use Workman::Client;
use Workman::Queue::Gearman;
use Try::Tiny;
use Data::Dumper;

my $queue   = Workman::Queue::Gearman->new(job_servers => ['127.0.0.1:7003']);
my $client = Workman::Client->new(queue => $queue);

$client->enqueue_background(Echo => { msg => 'hello' }) for 1..10000;

こんなかんじで、共通化のインターフェースでenqueueできる。 ドキュメンテーションとか、configファイルから読む機能とか、簡単にworker serverを立ち上げるためのコマンドとかはこれからという段階だが、なんとなく雰囲気は伝わるかなと思う。 どうだろうか?

*1:gearman限定であればMasayuki Matsuki / Gearman-Starter - search.cpan.orgがある

yasnippet 8.0をupgradeしたらdefaliasしたmajor-modeを考慮しなくなったっぽい

EmacsWiki: C Perl Modeを参考に以下のようなコードを埋め込んでいた。

(defalias 'perl-mode 'cperl-mode)

perl-modeでいろいろなsnippetを作ってcperl-modeで使っていたけど、
どうもyasnippetをupgradeしたら動かなくなってしまった模様。(tagも8.0までしか付いてなくてどこで動かなくなったのかはcommit追わないとわからなくてめんどくさくなった)
本来はcperl-modeでsnippetを作るべきだし、曖昧さを解消しているので歓迎するべき変更だとは思うけど、原因なかなか分からなくてハマった。

#dwangocpp に参加するためにLTしてきた

C++

僕は8年くらいC++を書いていなかった。今年の前半はC++11を学ぶことにしていたので少しづつ触ってはいたが、流石に8年ぶりとなるのでC++の基礎的な文法から学び直すこととなり、せいぜいhello worldに毛が生えた程度のものしか書いてこなかった。autoなどC++11で導入された主要な機能を試す程度だ。
よりC++11について深い理解を得るための機会と実装ネタが必要だと感じていたところだった。

ドワンゴC++勉強会 #1が開催される事を知った。
江添とでちまるとボレロ村上の闇の共演という珍妙なサブタイトルを理解するのに苦しんだが、
どうやらこの勉強会は、Cプリプロセッサメタプログラミングと、コンパイルメタプログラミングについて学ぶことが出来る勉強会のようだ。
僕もYAPC::Asia 2014perl 5 meta programmingというトークを応募している程度にはメタプログラミングには関心が深い。これは面白そうだ!と是非参加したくなった。
しかし、定員は既に埋まっており、補欠登録をしている人は100人を超えそうな人数でとても入れそうになかった。
また、諸般の事情により貧相なネットワーク環境しか無い僕がニコ生配信を見るのは厳しかった。
しかし、僕はLT枠には空きがある事を発見した。C++erは至る所で闇の軍団と呼ばれている程に恐れられていると聞いているので、発表する敷居が高いということだろうか。
たしかに、既に応募されているLTもC++をdeepに利用している人のLTである事は容易に分かるタイトルであった。
僕は悩んだが、これは絶好の機会であるので、行くべきである。最近はTOMLのparserをperl5で実装していたので、parserの実装をネタにすることにした。C99を含む他言語をある程度は理解しているC++初心者には適度な難易度であろう。また、他に並行して4つ程ライブラリをperl5で開発していたが、この難易度であれば恐らく問題はなかろうという目論見だった。
そうして、C++初心者書がC++11でparserを書いてみた話という話でLTを応募し、無事参加する事が出来た。主催の@EzoeRyouさん、株式会社ドワンゴさんのご厚意に感謝致します。

内容としては予告通りの内容で、資料も公開して頂いている。

LT資料にも書いているがconstexprの可能性は素晴らしいと思った。
inline関数と違い、コンパイル時に処理し、定数化出来るという違いは大きい。
parser generatorの実装もできるだろうと思った。実際、発表者の id:boleros 氏は既に bolero-MURAKAMI/Sprout · GitHub でSprout.Weedという機能として実装していると伺った。いずれ試してみたい。
Cプリプロセッサマクロでループを表現する手法など高度なマクロの利用方法も素晴らしかった。既に洗脳が解けたので真似する気はあまり無いが、実際、マクロを利用したい場面は多い。僕も学生の頃にTerm::ANSIColor相当の機能を持つマクロ群を書いた事があるし、最近ではAndroid NDKでpicohttpparserのbindingをC99で書いたときにロギングのために__func__などを仕込むマクロを書いた。やろうと思えばなんでも出来るという勇気を貰った。(小並感)
C++の歴史は既に何度か資料を読んでいたが、日本のC++ WGの近況については衝撃を受けた。海外のWGではどのように運営されているのか少し興味が湧いた。

さて、僕のLTの話だが肝心の実装は間に合ったのか?結果から言えば、実装は間に合わなかった。LTは実装の途中で便利だと思ったC++11の機能を紹介し、お茶を濁した。エンジニアとして成果物が一切無いという屈辱のLTをすることとなった。*1

LT資料*2

落ち葉拾いであるが、perl5もリファレンスカウント方式のGCなのでshared_ptrが持つ根本的な問題についてはある程度は理解しているつもりだ。その上で、素晴らしい機能だと思う。
相互includeについては、当然ながら宣言はhppに、実装はcppにという具合に分割しており、#pragma onceを付けていた。宣言の時点で相互includeが発生したが為に困ってしまった。*3

今年の前半の最終日である今日中には完成させたいと思っているが、現状の設計ではconstexprを使う場面はやはりなさそうである。いずれconstexprを使ってparserをコンパイル時に生成する事も試したい。具体的にはstrptime(3)や正規表現エンジンを実装できたら有用だと思っている。

最後に改めて、主催の@EzoeRyouさん、株式会社ドワンゴさんに感謝を申し上げます。ありがとうございました。

*1:その為か@EzoeRyouさんに本の虫: ドワンゴC++勉強会#1を開催したで実際のLTの内容に一切触れずお茶を濁すような気遣いをさせてしまったようだ。

*2:写真はイメージです

*3:後の試行錯誤により、pragma onceではなくifndefによって重複読み込みを回避すると再定義エラーは出なくなったが、結局定義に必要な型情報が得られずコンパイルエラーとなってしまった。

Macにエコーをかけて発言させるfunctionできたよー!

Mac OS Xに何故か入っているsayコマンドをご愛用の皆様、いかがお過ごしだろうか。
sayコマンドはmacに様々な言語で様々なワードを発言させる事ができ、
非常に便利なので公私共に多用している方も非常に多いと思う。

しかし、あまりに多用していると、なにか物足りない。
さりげなさすぎて気づけない。ライブ感が無い。など、
様々な悩みを抱えると思う。

そういうときはビールでも飲めばいいのだけれど、
仕事中にビールを飲むわけにはいかないし、
中にはビールが嫌いで日本酒しか飲まないような人も居るだろう。

そういう人のためにライブ感を提供する方法として、sayにエコーを掛ける方法を考えた。
お使いのmacでこれを.zshrcなどにいれておくといい。

function say-with-echo {
    for i in `seq 2 8`; do
        say "$@" &
        sleep 0.0$i
    done
    wait
}

すると、以下のようにsayコマンドと同様に使うだけで簡単にエコーをかけることができる。

say-with-echo x-video

如何だろうか?エコー感は感じられただろうか?スペックは足りているだろうか?
少しでもライブ感が高まれば本望だ。今日もビールがうまい

gitで新しくブランチを切るベストプラクティス

git

普段から普通にやっている方法です。

git fetch
git checkout -b $BRANCH_NAME origin/master
git push -u origin $BRANCH_NAME

git fetchでoriginを最新にして、origin/masterからブランチを切ります。
これで、プロジェクトの最新の状態からbranchを切る事が出来ます。
現在どのbranchに居るかを気にせずとも、branchを切る元を間違える事がないので安心です。
(例えばうっかり関係ないtopic branchから切ってしまう。といったことを気にしなくて良くなります。)

また、git push -u origin $BRANCH_NAMEすることにより、
リモートブランチがupstreamとして紐付く為、いちいちgit pull origin $BRANCH_NAMEとかしなくて良くなり、うっかり違うブランチをpullするというような事故を防げます。

というやりかたがベストかなーと思っていますがより良い方法があれば知りたいです。
追記: git 1.9未満ではこの上でgit config push.default upstreamにしておくと安全です。git config push.default currentだと最初のpushが若干楽になりますが、upstreamのがカタイです。お好きな方で。*1
なお、git 2.0からはgit config push.default simpleがデフォルトになったので、git 2.0使おうぜもアリだと思います。

*1:もちろんですが、globalに適用したいときは--globalオプションを付けましょう。

Gotanda.pm #1 告知までにやったこと

忘備録です。

ざっくりやったこと

  1. Gotanda.pmを立ち上げる
  2. 大まかなスケジュールを立てる
  3. 会場を探す
  4. 日程と詳細なコマ割りを仮組みする
  5. イベント参加登録サービスに登録する
  6. 開催を告知する

Gotanda.pmを立ち上げる

Yokohama.pmは遠いし、Shibuya.pmは最近開催していないし、もっと近くで頻繁に開催するPerl Mongerな技術コミュニティを作りたい!みたいな事を考えて立ち上げました。
自分も発表などで参加したいので、開催コストを徹底的に効率化して開催サイドでも参加出来るカンファレンスにして、カジュアルに誰でも開催できるような感じにできれば良いなと思っているので、楽をするために思いつくことはどんどんやっていこうと思っていて、立ち上げのタイミングでもそれは実践しています。


まずは、WebサイトとGoogleカレンダーを用意しました。WebサイトはGotanda.pmについて調べたときにざっくりとした概要と最近の状況が分かると良いということで用意しました。
また、Googleカレンダーは自分のカレンダーにインポートしておけば勝手に自分のカレンダーにGotanda.pmの開催予定が入って、予定が空いたときにさくっと登録して行けたりするし、登録してたけど忘れてた!みたいなことを減らせるのでよさそうということで入れました。
また、Rijiを利用することでRSSも配信して、Gotanda.pmについての情報が自分のフィードリーダーに流れて来なかった!みたいなケースも防ぎやすくしました。


余談ですが、最近ノンデザイナーズ・デザインブックを読み始めたので、
その内容を実践する場としても使ってみました。とはいってもmargin整えて離すべき要素と近づけるべき要素を考慮してラインを作ったくらいで、
配色とかもセンスがないかんじで、デザインできる人が見たら笑ってしまうような代物ですが、レイアウトはそこそこ見やすくできたかなということで、
実践できて良かったなぁと思いました。こんなかんじです。
ただ、これをこのまま運用するのは恥ずかしいのでデザインテロとかお待ちしております!!!

ノンデザイナーズ・デザインブック [フルカラー新装増補版]

ノンデザイナーズ・デザインブック [フルカラー新装増補版]

テーマを決める

発表したい内容がある人は何を話しても構わないと思うのですが、なかなか決められない人も多いと思います。(自分自身そういう経験がありました)
そのため、テーマは一応決めておくとハードルが下がるのではないかということで僕の独断と偏見でテーマを決めました。
第一回のテーマは「Webサービスを支える技術」ということで普段の業務でWebサービスを作ってるひとにはとっかかりやすいお題になったのではないかなと思います。

大まかなスケジュールを立てる

Gotanda.pmはアクティブに活動を続けるために、3月/6月/9月/12月にカンファレンスの開催を予め決めています。
今回は6月ということで、じゃあどのように開催するかというのがあるわけですが、
まず土日の開催はやめました。貴重な休日ですので先の日程でも既に予定が埋まっていたというケースも大いに想定出来ますし、
会場によっては土日の開催が厳しい場所もあるので選択肢が狭まります。
また、感覚的なはなしですが、仕事終わってさくっと参加してさくっと呑んでさくっと帰るみたいな感じのが充実感あって濃くなっていい気がしてます。
そういうわけで僕の独断と偏見でこちらも平日の19:00~21:00くらいと決めました。*1
これで、『6月の平日の19:00~21:00くらいに借りれる』という条件が作れたので会場を探す条件が少しはっきりしました。

会場を探す

いよいよ会場を探します。今回は以下の項目について予め決めました。

希望時間帯
17:30~(準備時間含む)
希望の曜日
平日(可能であれば水曜日):
喫煙の可否
喫煙所があるとベター
プロジェクター利用の可否
必須
途中入退場の可否
出来るとうれしい
収容人数
最低20人(30人くらい余裕持って入れるとうれしい)

また、どれくらいの時間、会場を借りなければならないか。いつまでに現状復旧出来るか。を考えるために、
スケジュールも超ざっくり仮組みしました。
準備時間は初回なので苦労しそうだなということで多めに確保しています。
トークは2時間くらいできるといいかなぁという感じでこのように組みました。
最初は以下の様な感じでした。

時間 内容
17:30~18:30 準備時間
18:30~19:00 受付
19:00~21:00 内容
21:00~22:00 会場復旧

この条件で自分の勤務先のオフィスの会議室が使えそうだったので今回はそこを借りる事にしました。

日程と詳細なコマ割りを仮組みする

30人くらいなので、なんとなくですが、
20minくらいのtalkを3つくらいとLT6つくらいで、
ちょうどいいかな〜と思って切りました。

時間 内容
18:30〜19:00 参加者受付
19:00〜19:20 Talk(1)
19:20〜19:40 Talk(2)
19:40〜20:00 Talk(3)
20:00〜20:10 休憩
20:10〜20:15 LT(1)
20:15〜20:20 LT(2)
20:20〜20:25 LT(3)
20:25〜20:30 LT(4)
20:30〜20:35 LT(5)
20:35〜20:40 LT(6)
20:40〜 懇親会

ここは会場を借りる時間さえ決まっていれば、
その中でてきとうに調整してしまえばいいはずなので、
さくっと決められました。

イベント参加登録サービスに登録する

イベントの参加者とかを手で管理するのはつらいので、
イベント参加登録とかを管理してくれるサービスをつかいます。

いろいろありますが、今回はZussarを使わせて頂きました。
理由としてはAPIが認証を要求せず、JSからでもわりかし使いやすそうだったので、
Gotanda.pmのweb-siteに組み込みやすそうだなぁと思ったのが一番大きいです。


ここでやることはシンプルで上で決めた内容を書くだけです。
日時と場所を明示してスケジュールの表を貼ればそれでわりかし十分そうでした。


実際に使ってみたところ、意外と困ったのがイベント内容編集でした。
見た感じのままに編集出来るのはそれはそれで良いのですが、
Webサイトから文言だけコピペしてこようと思ってもスタイルごとコピペされてしまったり、
表をコピペしてきてもスタイルごとコピペされてしまい、
Zussarのイベントページのデザインを崩してしまったり、
表を作ろうにも下書きとして温めておいた表をそのまま使えず、
結局1セル毎に手作業でコピペしなければならず、苦労しました。
MarkdownやTextile等が使えれば良かったのですが、そうではなかったので、
次回以降はZussarで文言や表を先に作るか、あるいは他のサービスを使おうかと考えています。

開催を告知する

ZussarのイベントページができたのでそのURLを張りつつRijiで記事を書きます。
Googleカレンダーにも忘れずに登録します。
これであとで見返しても、ああ。Gotanda.pm#1開催したんだなぁと分かって便利になりました。

感想

いろいろあって大変だったのでいろいろ自動化したりして効率化していきたいなぁと思いました。
気持よく開催出来るよう引き続き準備がんばります!

*1:実際、これは短いかもしれないので次回からは長くするかもしれません

about.meをやめてオレオレabout.meを作った

もう去年の11月頃の事になるが、仕事の一環であるイベントに参加した。
イベントの参加者のエンジニア志向の学生と名刺やtwitter idなどを交換した。


当時の僕のtwitterのプロフィールなどに載せているURLはabout.meだった。
about.meは良いサービスだ。お手軽に自己紹介ページを公開出来る。似たようなWebページをわざわざ書かなくていいし、車輪の再発明を防ぐ。
しかし、当時のabout.meはスマートフォン向けにUIが最適化されなかった。スマートフォンでWebを閲覧する人が多い時代にこれは致命的だった。(現在はスマートフォン向けにもUIが最適化されてるようだ)*1
また、僕はWebエンジニアの端くれだ。仕事ではPerlでバックエンドサーバーのコードを書き、必要があらば新しいミドルウェアの導入からサーバーの構築、HTML/JS/CSSのコーディングから、AndroidアプリのためにJavaでゴリゴリロジックを組んだり、JNIを使ってCライブラリのバインディングを書く事もある、なんでも屋なWebエンジニアだ。
Webエンジニアのくせに自分のWebページすら自分でコーディングしてないのはどうなのだろうか。自己紹介ページ程度すら自分で組めないのか?今日会った学生にはあのひとは自身の自己紹介のWebページすら組めないようなエンジニアだと思われたりしないか?口だけのクソエンジニアだと思われたりはしないか?もしかしたら自分は死んだほうがいいのでは?などいろいろなもやもやした思考が駆け巡った。


そんなもやもや家に帰ってから1時間くらいでデザイン組んで2時間くらいでごりっとコーディングした。現在の様子がこれである。
http://karupas.org/


デザインは zurui-design // Speaker Deck を参考にしつつ、背景画像は適当なフリー素材をググって見付けて利用した。
CSSはそんなに得意では無いのであまり自信が無いがとりあえずゴリッと書いたきがする。あんまり覚えてないけど、たぶんCSS得意な人からしたらだいぶクソなCSSなんだろうとおもう。
CSSフレームワーク使ってたらなめられそうだからnormalize.cssだけ使ってごりーっと書いた。
コンテンツもてきとーにGithubとかから取ってきて埋め込むことにした。
モバイル向けのWebアプリを仕事で作ってるのにスマートフォン対応しないのもどうなんだろうと思って、昔ながらのリキッドレイアウトに加えてフレキシブルボックスを使ってなんちゃってレスポンシブな感じのを実装した。
でも、iPhoneとかで横幅が揃わなかったり、うまいこといかなくて次の週くらいにCSSをなにか修正した気がする。どう修正したかはあんまり覚えてない。
Angular.jsを初めて使ったがドキュメントが充実してて、サンプルコードも多く、あまり苦労せずに組めた。


当時のコードはこんな感じだった。(是非HEADのコードもみてもらいたい)
https://github.com/karupanerura/Profile/tree/e9e1b49b0a1bfe94f2918f17ca40587de0ea3b3b


もやもやした思いをコードを書くことによって晴らすことができて、エンジニア感あったし、いいかんじだった。
コード書き始めたのが24時頃で、次の日は仕事で、なるべく短時間でつくりたくてタイムアタック感あって楽しかった記憶がある。
あと、興味あったけどネタがなかったanguler,jsを試すにはちょうどいい題材だった。
こういうの楽しいしみんなやると面白いんじゃないかと思った。

*1:もしかしたら当時も既にこの施策は実施されていたかもしれないが長らく自分のabout.meを見ていなかった僕のabout.meに対する印象は昔のままだった。