limitusus’s diary

主に技術のことを書きます

PerlでGoogle Calendar APIを勉強

アラートのメール通知がきたらGoogle Calendarに記入しておくとあとで振り返るのが簡単なんじゃないかなーと思ったので、まずはお勉強から。

要素

できるようになってから振り返ると、以下の要素を理解する必要があった。

これからそれぞれの要素について書いていこうと思う。
コードはほぼコピペだが、エラー処理(status=200でないとき)の処理は簡単のため省いている。

続きを読む

PerlでTwitter API SSL化に対応するたった1行

手元でTwitterの古いpostを削除するスクリプトをcron実行してるのですが、Twitter APIってSSLのみ対応になったのをすっかり放置してしまっていました。
cron実行に失敗してメール通知が来たので1週間くらい経ってようやく対応。

Net::Twitterを使っているのでバージョンを上げて、アプリ側では1行追加するだけ。

    my $nt = Net::Twitter->new(
        traits => [qw/OAuth API::RESTv1_1/],
        consumer_key => $config->{consumer_key},
        consumer_secret => $config->{consumer_secret},
        access_token => $config->{access_token},
        access_token_secret => $config->{access_token_secret},
        ssl => 1,  # ここを追加
    );
    if (!defined $nt) {
        die "Authentication Failed: $!";
    }

無事動きました。

Parallel::Fork::BossWorkerAsyncがいい感じ

先日 id:hirose31

  • 並列処理はParallel::ForkManagerとかParallel::Preforkが定番だけど、もうちょっと効率よくやりたいこともある
  • P::ForkManagerはタスクごとにforkするので負荷の分散は綺麗にできるが、タスクの数だけforkが発生して効率がよくない
  • P::Preforkだとfork回数は並列度分だけだが、タスク開始前にタスクの分配を完了させないといけない
  • Cでmultithreadならmaster-workerモデルでmasterにqueue持ってmutexでロックするような練習問題とかある
  • けどPerlでmultithreadやりたくないし、実現するとすればsocket経由でタスクを渡していく感じにしないといけないか
  • 誰かCPANに上げてるんじゃないかなー
  • なければ作るかー

的な話をしていました。

で、metacpanを漁っていたところ、それっぽいのを見付けました。Parallel::Fork::BossWorkerAsync

計算モデル

このモジュールは事前に1個のbossとk個のworkerプロセスをforkし、masterが都度タスクを生成して登録していきます。
workerはただただwork_handlerで与えられたsubを実行していき、計算結果をreturnします。
workerの計算結果が帰ってくるとmasterではresult_handlerで与えられたsubが呼び出されます。(たとえば結果を集めるオブジェクトに登録する)
最後にshutdownを呼び出すとbossと全workerが終了します。

プロセスツリーとしてはこうなります。

  └─perl,18371 bwa.pl # アプリケーション
      └─perl,18372 bwa.pl # boss
          ├─perl,18373 bwa.pl # worker
          ├─perl,18374 bwa.pl # worker
          ├─perl,18375 bwa.pl # worker
          ├─perl,18376 bwa.pl # worker
          └─perl,18377 bwa.pl # worker

bossプロセスは各workerとアプリケーションとタスク/結果のやりとりをするためにひたすらselect(2)を呼んでいるプロセスです。
workerプロセスはbossからタスクを受け取って処理したらbossに結果を返します。
アプリケーションプロセスはbossとだけ直接通信し、タスクを投げて結果を受け取ります。

利用例

大したものではないですが、podに書かれていないようなモデルでの利用例。

workerは単に1秒sleepし、自分のjob idを返します。
masterは返されたjob idを配列に追加していって最後にdumpします。
それだけ。

この例ではk=5としていて、最初に5プロセスが生まれた後はプロセスの交代は起こっていません。
タスク供給はちょっと不定期な感じにするために、17個ずつ供給し、終了次第次の17個を供給してます。
53 / 17 = 3あまり2
17個のタスクを5並列でやると4秒かかるので、
4 * 3 + 1 = 13秒で実行が完了します。

#!/usr/bin/env perl

use strict;
use warnings;

use Parallel::Fork::BossWorkerAsync;
use Data::Dumper qw(Dumper);
use Time::HiRes qw(gettimeofday);

my @Finished_Jobs = ();
my $PARALLELISM = 5;
# sleep time
my $NUM_WORKS = 53;
my $WORKS_AT = 17;

# この時点でworkerがforkされた
my $bw = Parallel::Fork::BossWorkerAsync->new(
    work_handler => \&work,
    result_handler => \&rhandler,
    worker_count => $PARALLELISM,
);

my $thrown_work = 0;
while($thrown_work < $NUM_WORKS) {
    my @tasks;
    for my $i ($thrown_work .. $thrown_work + $WORKS_AT - 1) {
        push @tasks, { id => $i, sleep => 1 };
        $thrown_work++;
        if ($thrown_work >= $NUM_WORKS) {
            last;
        }
    }
    # タスク集合はここでディスパッチされる
    $bw->add_work(@tasks);
    # 実行完了待ちタスク数が得られる。この関数はblockしない
    while($bw->pending) {
        # "return"されたオブジェクトをそのまま受け取る。以下のように単に呼び出すとblocking
        my $ref = $bw->get_result;
        # P::F::BossWorkerAsyncのレイヤでエラーがハンドルされた場合は ERROR というkeyにメッセージが入ってくる(タイムアウトを指定した場合など)
        if ($ref->{ERROR}) {
            print STDERR "ERR: ". $ref->{ERROR};
        } else {
            print $ref->{job} . "\n";
        }
    }
}

# workerプロセスを終了させる
$bw->shut_down;

print Dumper \@Finished_Jobs;

# worker側で各タスクに対してcallbackされる
sub work {
    my ($job) = @_;
    my $id = $job->{id};
    my $t0 = gettimeofday;
    print "$t0 start $id\n";
    sleep $job->{sleep};
    my $te = gettimeofday;
    print "$te end $id\n";
    return { job => $id };
}

# master側でタスク終了時にcallbackされる
sub rhandler {
    my ($result) = @_;
    my $job = $result->{job};
    push @Finished_Jobs, $job;
    return $result;
}

内部的にData::Dumperを使ったシリアライズをしているらしく、データの区切りに決め打ちのバイト列を指定する必要があります。そこはStorable::nfreeze/thawした方がいいんじゃないかな?と思ったりはします。
P::ForkManagerP::Preforkに比べると記述は増えますが、用途によっては便利なのでは?

Server::Starterに対応するとはどういうことか

StarletやStarmanと組み合わせてよく使われているServer::Starterですが、普段気にしないような部分を読む機会があったのでメモ。

Server::Starterは --port (TCP) や --path (Unix Domain Socket) を渡すとこれでlisten(2)して起動するworkerに引き渡してくれる。
これはfork(2)とexec(2)によってファイルディスクリプタを引き継ぐことにより実現されているが、ファイルディスクリプタそのものをどのように引き渡しているのか、という問題。
exec(2)により実行バイナリは差し換わってしまうので、プログラム中の変数により引き継ぐことはできない。

Server::Starterではこれを環境変数SERVER_STARTER_PORTにより実現している。

おおよそ以下のような感じ。

FD = integer
EQ = '='
SEMICOLON = ';'
SERVER_STARTER_PORT = PORT_DESCRIPTION ( SEMICOLON SERVER_STARTER_PORT )
PORT_DESCRIPTION = PORT_NAME EQ FD
PORT_NAME = character+

PORT_NAMEはソケットの種類によって違って、TCPであればポート番号(8080)とかホスト名:ポート番号(localhost:8080)、Unix Domain Socketであればそのパス(/path/to/app.sock)となる。

PODにも書いてあるServer::Starter::server_portsはこの環境変数をほどいてPerlのハッシュにして返してくれる小さなサブルーチンとして実装されているので、workerがPerlであればこれを使えばよい。
workerは環境変数から受け取ったファイルディスクリプタの番号をfdopen(3)して(あるいはそれすらもせずに)そのソケットを利用することができる。

ところで別にworkerがPerlであることは要請されていない。

続きを読む

YAPC::Asia 2013 Staff Report

去年の YAPC::Asia 2012にStaff参加してきた - Limitの日記 に引き続き、今年も YAPC::Asia 2013 のStaffとして参加してきました。
今年も「ブログを書くまでがYAPC::Asia」ということで、書きます。

今年は僭越ながら多目的教室2という部屋のリーダーを仰せつかり、メンバーをまとめる役割となってしまいました。
この部屋で何か問題があったら私のせいです。

Staff Kickoff

Staffは7月頃に1度集まり、kickoffという名の飲み会をやっていました。
ここでは主に顔合わせ。去年と同じく名刺交換などです。

前夜祭

実は前夜祭の前にコアスタッフと呼ばれる一部メンバーが9割方の準備を済ませてくれています(ほんとうにありがとう!)
前夜祭の日に集まったスタッフは残り1割の準備をやります。
ひたすら来場者に渡すノベルティの準備作業をしたり、椅子スポンサーの準備をしたり、会場の展示物の準備をしたり、、、
例年の前夜祭では受付の開始前にはノベルティは準備が終わるのですが、今年は分量が多く、受付開始しても準備が終わらない状態。
前夜祭の受付がバタバタしていたのはそのせいです。
それでもスタッフがいい感じに連携してTシャツを渡すことができていたので、かなりスムーズな受付になっていたと思います。
その裏では別メンバーがノベルティ詰め作業を続行していました。

受付が一段落した後もTシャツをサイズ別にトートバッグに入れ、整頓する作業が続けられました。
NOCチームはずっとNW敷設作業をしていました。
個人スポンサー/企業スポンサーの提灯のセッティングもこのあたりで。
企業スポンサーの提灯が階段上の手すりをわたるようにセットされていましたが、あれもその場のスタッフのアイデアです。

作業は施錠の21:00まで続きました。

1日目

本番初日、8:30集合、9:00開錠ということで、朝から慌ただしい感じでした。
多目的教室はこの日初めて入れるようになったので、そこから椅子スポンサーの準備、ビデオカメラ設置、電源準備、バックパネル準備などを行い、最初のセッションに備えます。
各部屋ごとに担当者のLINEグループをつくり、メンバーはそこでその部屋固有のやりとりをできるように準備。
スタッフも抜けたい時間があったり、他の会場の準備を手伝う予定ができたりするので、セッションごとに担当を割り付けます。
そのあとは各セッションでタイムキーピング、録画がされているかを確認、幕間に流すCM、発表者への説明などを行っていました。
懇親会の間には翌日に備えた細々とした準備をしたり、投票システムのチェックをしたり(実は告知前にシステムのバグを発見していました/もちろんリリース前に修正済)。
懇親会は後半だけいたのですが、ご飯おいしかったですね。

この日は懇親会の後比較的早めに作業が終わり、平和に終わりました。

2日目

この日は基本的に1日目と同じです。
LTが行われる間に大量の撤収作業が行われ、とにかく早く全てを片付ける、ということに追われていました。
ということでやはり発表はほとんど見ていません。動画に期待。

大きな物の運び出しは運送業者の方がやってくる時間が決まっているので、期限があるものからとにかく片付ける。
なかなか物は減らず、メインホールで発表が行われている間も含めて数時間にわたる撤収作業が行われていました。

Staff として。

YAPC::Asia Staff としては2年目、YAPC::Asia の参加者としては3年目でした。
去年も一緒にStaffとして仕事をした方とは相変わらず、今年からの方とも仲良くなれて、人間関係が広がったんじゃないかなと思います。

Hacker の技術をお披露目する場を作る手伝いができるって、楽しい。

実は通しで見られたセッションは2つくらいだったりしますが、その辺は後日公開の動画で補完しておきます。

今後の YAPC::Asia は?

クロージングでは今まで YAPC::Asia を主体となって運営してきて下さった牧さん、櫛井さんの引退が発表されました。
スタッフもこのとき初めて聞かされたことでした。世代交代の時期ということなのだと思います。
来年も YAPC::Asia を誰かが開催できるかどうか、わかりません。今回1000人規模でしたが、牧さん櫛井さんが抜けた結果、この規模で開催はできないかもしれません。
それでも、縮小しても開催できれば、また大きくするチャンスがあるのだと思います。
もし開催されれば、そのときはまた運営として携わってみたいです。

クロージングでのスタッフ紹介のときにぱちり。

参加したみなさんへ

ブログを書くまでがYAPC::Asiaです。みなさん書きましょう。
書いたらYAPC::Asia 2013 感想エントリまとめ(募集中) | YAPC::Asia Tokyo 2013へ。
アンケートもメールが届いていると思うのでお願いします!


これで私のYAPC::Asia 2013も終了です。

ときどきTech系イベントには参加しているので、もしどこかで見掛けたら声かけてください。
では!

MacBook Air 11インチ用ケース

4年くらい前に800円くらいで買ったケースがだいぶボロボロになってしまったので、いっそのこと、ということで新しいのを買うことに。
近所の電器店で眺めて、収まりのよさそうなやつを選択。

いい感じ。

だが、結果的にはAmazonで買った方が安かったじゃないか。。。

MacのDockが暴走した

最近メインで使っているのはMacbook Air (Lion) なのだけど、数日前から妙に動きが重くなり、ファンもうるさくなったのでちょっと調べてみた。
まずhtopで長めてみると Dock がCPU 100%食っていた。原因はまずこれだ。
減少としては17秒くらいに1回DockがSIGABRTを受けて死んで、また起動してCPU 100%に貼り付く。を繰り返す状態だった。

検索したところ、VMware関係が原因だとかいうのが目立つが、どうやら違うらしく、最終的に以下の記事に行きついた。
https://discussions.apple.com/thread/3684623?start=0&tstart=0

まずは ~/Library/Preferences をまるっとbackupしておく。
で、とりあえず ~/Library/Preferences を消してみる。
そうすると次にDockの再起動時には直るので、ここが原因らしいと確認できた。
あとはbackupを戻して再起動して再現させ、設定ファイルを消しては再起動後に直るかどうかを順番に試していくだけ。

今回は最終的に

rm ~/Preferences/ByHost/com.apple.dock.AE697267-4B85-5FC7-BF96-EBE7847EF12B.plist

により落ち着くことが確認でき、復旧完了。

あー大変だった。