ただ単にプログラミングの様子を流すという試みw
技術者じゃないあなたもプログラミングをやった気になれる誰得動画です。
楽しんでいただければ幸いですw
ただ単にプログラミングの様子を流すという試みw
技術者じゃないあなたもプログラミングをやった気になれる誰得動画です。
楽しんでいただければ幸いですw
Mongoose(MongoDBのODM)を使って、コレクションからほんの10万ほどのドキュメントを処理するスクリプトを実行した時でした。処理が固まってしまうのです。なぜでしょう?
各ドキュメント処理では、コールバックを伴う非同期的な処理を含みます。
問題のCoffeeScriptのコードは以下のようなイメージです:
Foo.find()
.sort value:-1
.stream()
.on 'data', (d)->
someTask d
someTask = (d)->
doAwesomeJob (result)->
console.log "Great!"
モデルFoo
のドキュメントを全て読み込み、各ドキュメントをストリームに流し込んでいます。
メモリを節約するためにストリームの手法を採用しています。
doAwesomeJob
は、例えばAPIを叩くとか、そういう非同期な処理です。
しかし、doAwesomeJob
のコールバック関数がなかなか呼ばれない。遅い。ついには全く呼ばれなくなる。
Node.jsアプリケーションはシングルスレッドです。
下図のように、イベントループ機構が備わっていて、Event Queue
に溜まった処理キューを順次消化していく仕組みになっています。
(via http://misclassblog.com/interactive-web-development/node-js/)
つまり、Node.jsはひとつずつしかキューを処理できないのです。
上記スクリプトで、ストリームのイベントのInvocationが、大量にこのイベントキューに押し寄せている事を想像してください。
doAwesomeJob
のコールバックは、その非同期処理の完了時点で最後列にエンキューされます。
しかし、非同期処理の間にドキュメント読み出しイベントの処理キューが大量に溜まります。
その結果、doAwesomeJob
のコールバックが呼ばれるまでに時間がかかってしまっているのでした。
似た問題に直面している人がいました。
RabbitMQのメッセージキューがいちどに大量に来た時に、イベントループのキューが溢れるようです。
問題は僕のケースより少し深刻なようです。見なかったことにしましょう。
溢れるのなら、分割すればいいですね。
以下のように変更を加えました:
processNext = (offset, num, on_completion)->
i = 0, j = 0, closed = false
Foo.find()
.sort value:-1
.skip offset
.limit num
.stream()
.on 'data', (d)->
++j
someTask d, ->
++i
if i==j && closed
processNext offset+i, num, on_completion
.on 'close', ->
closed = true
on_completion() if j==0
someTask = (d, callback)->
doAwesomeJob (result)->
console.log "Great!"
callback()
processNext 0, 100, ->
console.log "done!"
ドキュメントを100個ずつ読み出して、処理して、終わったら次の100個・・というフローに変更しました。
今のところ、これで上手く動いています。
でもこのコードは少し汚いので、よりエレガントに書くためにasyncを使うことをお薦めします。
drain
で完了をフックするといいと思います。
このストリームの分割では、ストリームを処理している間にドキュメントが追加・削除される事を想定していません。
コレクションの変更まで考慮する場合は、想定される変更内容によって変わると思います。
ご参考まで!
最近、チャットツールをHipChatからSlackに乗り換えました!
いわゆるチャットツールです。技術者向け。
SlackはHipChatと違ってUIがリッチで分かりやすいです。オシャレ!
HipChatと同じくAPIを備えており、GitHubやAsanaなど様々なサービスと連携させる事ができます。
そして、タイトルにもあるHubotとも連携させる事ができます。
チャット上で使えるボットです。Node.jsで書かれています。GitHub社が開発しました。
ボットというとTwitterのボットを想像するかもしれませんが、基本は同じです。
ボットに向けて、決まった書式でメッセージを送ると、そのメッセージに応じた処理を行います。
例えば、Jenkinsのビルドを実行したり、アプリケーションをデプロイしたり、ネコ画像を拾ってきたりします。
従来は個別のターミナル内で行っていたタスク指示が、チャットウインドウに移ります。
この事のメリットは主に二つあります。
ビルドやデプロイなどは、いつ誰がやったのか残っている事が望ましいです。
また、チームワークにおいてはそのタスクが属人的にならないようにする事が重要です。
タスク実行をチャットウインドウから行う事で、直接的な作業が会話にシームレスに混ざります。
それによって、デプロイなどの手順や気をつけるべき点が自然と共有される形になります。
このようにチャットを使ったサーバ運用をChatOpsと呼びます。
Slack用Hubotプラグインがあるので、書かれている手順に従えば簡単に設定できます。
日本語の情報もnanapiなどに掲載されています。
しかし、どれもHubotをHerokuにデプロイする場合の手順です。
いやいや、俺は自前サーバにHubotを稼働させる場合の手順が知りたいんだ。
という訳で、このページでは自前ホストのHubotとSlackを連携させる手順について説明します。
既に自前サーバで動作している方は読み飛ばして下さい。
$ npm install -g hubot coffee-script
$ hubot --create [path_name]
$ cd [path_name]
$ npm install hubot-slack --save
$ ./bin./hubot
Slackの以下のページから、環境変数に設定する値を取得します。
それぞれ、環境変数に設定します。
$ export HUBOT_SLACK_TOKEN=<token>
$ export HUBOT_SLACK_TEAM=<team>
$ export HUBOT_SLACK_BOTNAME=<bot name>
Hubotは、HTTPインターフェースも備えています。これはデフォルトで8080
ですが、PORT
の環境変数を指定することで変更できます。
$ export PORT=9999
ファイヤーウォールの中にいる場合は、このポートで外からhubotにアクセスできるようにしておきましょう。
EC2の場合はセキュリティグループを確認しておきましょう。
そして、あなたのHubot HTTPインターフェースへのURLをSlackのHubot URLの欄に記入します。
これで、SlackはHubotへのメッセージをこのHTTPインターフェースに送信するようになります。
さあ、Hubotを起動してみましょう。
$ ./bin/hubot --adapter slack
成功です!
Enjoy ChatOps!
どうも、食あたりで悶絶中のnoradaikoです。
気を紛らすためにブログを書きます。
僕はiPhone 3GSの時代からずっとiPhoneなんですよね。
おサイフケータイやスマート決済というものが日本では普及していてとても便利なのに、全くその恩恵に与れないのは勿体ないと感じたのがきっかけです。
しかし、それだけのためにキャリアを2台分も契約するのはちょっとコストパフォーマンスが悪すぎる。
そこで、キャリア契約無しのAndroidスマホでおサイフケータイを使おうと検討したところ、いろいろ注意点が分かったのでここにまとめたいと思います!
Androidスマホは実に沢山の種類が出ていますが、中にはおサイフケータイに非対応のものがあるので注意が必要です。
例えば、GoogleのNexusは非対応です。
僕は、HTC J Oneを購入しました!2013年の夏モデルです。
ちなみに海外向けのHTC Oneは非対応です。あぶねえ!
キャリアはauで、SIM無しです。
ここで衝撃的な事実です。
モバイルSuicaは、専用アプリの起動時にSIMカードが入っているかどうかを確認する処理があります。
もし購入したスマホがSIM無しだった場合、アプリが起動後に即終了します。
つまり、利用にはSIMが必要なんですね。
ちなみに、nanacoや楽天Edy、WAONは正しく設定できました。
上述の通り、モバイルSuicaを使うために正規のSIMカードが必要です。
実際に差してみるまで確証がなかったのですが、SIMは解約済みのもので大丈夫みたいです。
SIMカードには2つの軸で種類があるので注意です。それは、サイズとバージョンです。
購入したAndroidスマホの仕様欄をよく見て、どれが対応しているのか必ず確認しましょう。
HTC J Oneの場合は、下記のタイプでした。
au Micro ICカード(LTE)
詳しくは au ICカード(Wiki)を参照してください。
ちなみに僕はYahoo!オークションで購入しました。
無事モバイルSuicaを設定できたものの、一点気になる事があります。
それは、キャリア契約をしていないので当然通常はネットワーク切断の状態である事です。
ドキドキしながら改札にタッチしてみたところ、通れました!!
これは、NFCチップ間の通信で読み書きが完結しているためだと思います。
Android OSはもはや関係ないという事ですね。
アプリはチャージする際にインターネット通信をしている様子。
なので、もし外でチャージが必要になったらその場でインターネット接続が必要になります。
AndroidとiPhoneとのテザリング方法にはいくつかありますが、Bluetoothテザリングは出来ません。ペアリングが何度やっても失敗します。
ここではWi-Fiを使ったテザリングをしましょう。以下のページが参考になります。
iPhoneでインターネット共有設定が完了したら、Android側でWi-Fi接続の設定画面を開き、iPhone端末を選択しましょう。
あっさり繋がったと思います。
AppleはiBeacon推しのようですから、NFC搭載は微妙なところですね。
仮にNFCが搭載されたとしても、日本独自のおサイフケータイ規格には対応しない気がします。
現在、td-agentが正式にしているのは Ubuntu 12.04 LTS /Precise
と Ubuntu 10.04 LTS / Lucid
で、Debianは悲しいかな非対応。
現時点での最新版のバージョンは 1.1.18-1
だ。
precise向けのdebパッケージは、Wheezyでは libc6 (>= 2.14) の依存関係が満たせないので入れられない。
Debian Wheezy(7.1) に td-agent をインストールしようとして躓いたのでメモ を参照すると、どうやら少し古い v1.1.17-1 だと入れられるようだ。
念のため、本ページでもリンクを貼っておく:
v1.1.17-1のcontrolファイルは以下のようになっている。
Package: td-agent
Version: 1.1.17-1
Architecture: amd64
Maintainer: Kazuki Ohta <k @treasure-data.com>
Installed-Size: 76728
Depends: libc6 (>= 2.11), libssl0.9.8 (>= 0.9.8k-1), libxml2 (>= 2.7.4), libxslt1.1 (>= 1.1.18), libyaml-0-2, zlib1g (>= 1:1.2.2)
Recommends: ntp
Section: Network
Priority: optional
Homepage: http://treasure-data.com/
Description: A data collector agent for Treasure Data
最新版(v1.1.18-1)のcontrolファイル:
Package: td-agent
Version: 1.1.18-1
Architecture: amd64
Maintainer: Kazuki Ohta </k><k @treasure-data.com>
Installed-Size: 92187
Depends: libc6 (>= 2.14), libssl1.0.0 (>= 1.0.0), libxml2 (>= 2.7.4), libxslt1.1 (>= 1.1.25), libyaml-0-2, zlib1g (>= 1:1.2.2), libssl0.9.8
Recommends: ntp
Section: Network
Priority: optional
Homepage: http://treasure-data.com/
Description: A data collector agent for Treasure Data
libssl1.0.0
とlibssl0.9.8
の二つに依存しているのは置いといて、libc6のバージョンが2.14に上がっている。
Wheezyはlibc6
(v2.13-38)なので、問題はlibc6の依存関係。
debファイルをいじってv2.13に下げてインストールすると、以下のエラーを得た:
% sudo dpkg -i td-agent_1.1.18-1_amd64.deb
[sudo] password for nora:
Selecting previously unselected package td-agent.
(Reading database ... 66348 files and directories currently installed.)
Unpacking td-agent (from td-agent_1.1.18-1_amd64.deb) ...
Setting up td-agent (1.1.18-1) ...
Adding system user `td-agent' (UID 106) ...
Adding new group `td-agent' (GID 108) ...
Adding new user `td-agent' (UID 106) with group `td-agent' ...
Not creating home directory `/home/td-agent'.
Installing default conffile /etc/td-agent/td-agent.conf ...
insserv: script walknote-v2-share: service mongodb already provided!
insserv: script sspe-connection_queue_invocator: service mongodb already provided!
insserv: script pptp-etoile: service mongodb already provided!
insserv: script walknote-v2-push_notifier: service mongodb already provided!
insserv: script walknote-v2-usertrack_maintainer: service mongodb already provided!
/bin/echo: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found (required by /usr/lib/fluent/jemalloc/lib/libjemalloc.so)
start-stop-daemon: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found (required by /usr/lib/fluent/jemalloc/lib/libjemalloc.so)
.
libjemalloc.soが2.14を切望している。
この時点で、Wheezy向けにパッケージ作成するのは諦めた。
Treasure Dataさん、Wheezy対応ぜひお願いします。
朝起きたら、ログを表示していたターミナルがエラい事に・・。
上のスクショのようにアルファベットさえ文字化けしてしまう事ってたまにありますよね。
例えば、バイナリファイルを開いてしまった時とか。
この状態になると、いつもターミナルを一旦閉じて開き直していました。
が。
ターミナルを開き直さなくても元に戻せる方法があったのです!!
方法は簡単。
#!bash
echo ^[c
エスケープシーケンスのcを入力するので、下記のようなキーボード入力を行います。
echo <ctrl -V><esc>c<enter>
ほら!!
なおりましたね 🙂
tmux内のttyでも有効なので、お試しあれ^^
vimで長い文字列をコピペする時は、オートインデントやオートコンプリートをオフにするために、:set paste
でペーストモードに入りますよね。で、挿入モードになって、ペーストする。
最後に、ノーマルモードに戻って:set nopaste
で解除。
めんどい!!
そんなずっとペーストモードでいる事は無いので、挿入モードからノーマルモードに戻る時に自動で解除して欲しいですよね。
その方法をご紹介します!
チョー簡単。下記コマンドを打つだけ!
" Turn off paste mode when leaving insert
autocmd InsertLeave * set nopaste
Auto commandを使って、InsertLeave
イベント時にset nopaste
コマンドを実行するという意味です。
これを.vimrc
に書いておけばOKです!