横浜アリーナと日産スタジアムの予定を同時に取得し、Tweetする。Tweetしつつ同時に天気予報を取得する。先のTweetのstatus_idをin_reply_to_status_idにセットしつつ天気予報をTweetする事で連続tweetになる。Lambdaで毎朝1回実行している。Lambdaはメモリ使用量×処理時間で課金されるが、毎日約48MB×3秒で月に4.3GBなので、無料枠の400000GBに十分収まっている。同じようなbotをあと10万個ぐらい無料でデプロイできる。Lambdaについてぐぐると、最近はPython使ってる記事が多いというかほぼJavaScriptで書いてる記事が無いような?状況だけど、たぶんコールバック地獄がつらいからLambdaに向いてないとか思われてそう。coでだいたい解決するし、それどころか複数のIO待ちする処理を同時実行する等も書きやすいからJavaScriptいいと思う。console.log(result);})();babelでトランスパイルするとGeneratorを使ってwhileで回して待ち続ける感じになっているみたいだけどよくわからなかった。regenerator-runtimeが使われている。coで非同期処理を同期的に書くそういえばGeneratorで同期的に書けるやつっていうと、coを使ったことなかったな、と思いだして触りだした。coもまたPromiseを返す関数を同期的に扱える。console.log(result);});async/awaitと似たような感じになる。coの方はもっと高機能で、Generatorを包んだco自体がPromiseを返すのでさらに別のcoに食わせたりできる。coを使って書いた関数をライブラリとして提供して、それをmainのcoから呼び出して・・・というのを何重もできる。co.wrap(generator)すると即時実行せずに関数として定義できるのでcallにthisを渡せばES6のclass構文にうまくハマる。(略)coで複数の非同期処理を同時実行する上のようにイベント施設ごとのスクレイピングモジュールをそれぞれ作っておいて、coで同時に呼び出す。yieldにオブジェクトを渡すと全部同時に評価して、完了したら結果をまとめて返してくれる。下の例だとevents.arenaで横浜アリーナのイベント情報が、events.nissanで日産スタジアムの情報が得られる。});同時実行はyieldに配列を渡してもよい。ES6の分割代入を使ったら、tweetを投稿しつつ同時に天気予報を取得するのが綺麗に書けた。];coのエラー処理co自体がPromiseを返すので、まとめてcatchできる。スタックトレースがあればprintする。Lambdaはアプリケーションのプロセスではなくlambda、つまり関数単位でホスティングしてくれるサービス。Functionが起動して小さな仕事をしてすぐ終了するような感じで使われる。functionの起動さえ十分に速ければ、確かにずっとプロセスが起きていてメモリを専有しているような普通の実装よりも効率がいい。ためしにfunctionを作ってみるとわかりやすい。新規作成するとblueprint(ある程度できてるサンプルコード)から選択させられるので、node-execを選ぶと一番シンプルでいい。child_processでshellコマンドをexecするサンプルになっている。eventはevent.cmdを参照してchild_process.execするのに使われているが、これはActionsのドロップダウンメニューからJSON形式で編集できる。contextにはawsRequestIdやinvokeidが入っていて、これでAWS上のどういう環境で実行されているかが見れる。ローカルマシンで実行しているかとか判別するのにも使える。Configurationタブを見ると、index.jsというファイル名とhandlerという関数名が指定されている。基本形はmodule.exports.handlerを宣言したindex.jsというファイル1つで、これがAWS上でrequireされて呼び出される。"完了");}context.doneかcontext.failを呼ばないと設定したtimeout時間まで延々動き続けて課金されるので注意する。co自身から出るPromiseでエラーをcatchした時も、context.failさせる。Lambdaでnpmを使うファイル単一でformに貼り付けて実行するのではなく、zipで固めてアップロードでもいい。以下も一緒にzipすればいい。最大50MBまでいける。BlogLambda上でネイティブのOpenCV拡張を呼ぶために、EC2インスタンス作ってOpenCVをビルドして静的リンクして全部zipで固めている例もある。Lambdaを触ってみたかったので今回はzipでアップロードでやる事にした。Lambdaのnodeはv0.10.36なので、ちょっと古い。ES6(ES2015)を実行するにはbabelで事前にコンパイルしておく必要がある。0.10では動いているんだけどどうして動かないのかわからない。require-hookがLambdaでは効かないようになっているのかもしれない。事前にsrc/以下をbabelでES5に変換してからzipで固めた。中に実行に必要ないモジュールもたくさん混じってしまっているが、面倒なので全部まとめてbundle.zipに固めてしまった。npmが436個もあるけど11MB程度におさまったのでまあいいや。botはAWSの機能は何も使っていないので、ローカルでも動く。Lambdaで実行された時はindex.jsがrequireされてそこからexportされてるhandlerメソッドが呼ばれる。ローカルでも同じような動作をするrun.jsを用意して、そこから実行した。tokenが必要だが、こういうのはgitリポジトリにコミットしたくないので環境変数で渡したい。dotenvは.envファイルに書いた環境変数をloadできるので、.envファイルをzipに含めるようにした。serverlessもdotenv使ってる。process.env.ACCESS_TOKEN_SECRET});なおdotenvはloadしたファイルの中でしかprocess.envが上書きされないっぽい。プログラムの頭でやっても効果ない。Lambdaを定期的に実行するここまででだいたいスクリプトができたので、あとは毎朝実行するように設定する。eventを追加してcrontabのような記法で書く。タイムゾーンがUTCなので、イギリスだから日本から9時間時差がある。毎日23時(日本の8時)に実行するようにした。eventは英語版のドキュメントにのみ説明されている。日本語ドキュメントだと項目丸ごと無いのでしばらく困惑した。Lambdacrontabっぽいけど末尾にyearがある。Year)タイムゾーンを日本に設定するスクレイピングしてきたイベントのリストから今日開催されるものを判定して抜き出す必要があるので、タイムゾーンを日本時間に設定したほうが計算しやすい。Lambdaには環境変数を設定する機能が無い・・・ので、index.jsの冒頭で設定してしまう事にした。today.getDate();};やっぱserverless使おうかな気温もtweetさせたいんだけど、前日との差をtweetしたほうがいいのでSimpleDBか何かに書き込みたい。serverless使ったほうが良さそうな気がしている。あと、in_reply_to_status_idを使って連続tweetしてるんだけど処理が速すぎてtwitterに認識してもらえない。eventも1分ずらしてDBで最後のstatus_idを受け渡すかー、それならなおのことserverless使ったほうが良さそうだなとか思った。イベントソースが複数あってそれをGUIでポチポチやっていくのは混乱しそうなので全部コードでやりたい。混雑度予想と開場時間もほしい。shokaiLDRでazuさんのはてブを見たりもしているんだけど、自分JavaScriptガチ勢ではないのと流れが速いのとで追い切れなかったりする。最近はお風呂で湯船につかっている時にタブレットでmenthasを見てる。http://menthas.com/javascriptどういうアルゴリズムなのか詳細はよくわからないけど、わりと面白い記事が流れてきてしかもノイズが少ない。内容面白いのに3,4人しかbookmarkしてない記事も流れてきて掘り出し物感もある。vol.87のES6の特集を読みながら、ES6を勉強した。紹介されている機能をちょこちょこと試す細かいスクリプトを色々書いたりメモを取ったりしたのでまとめておく。APIを使ってたんだけど、そのインタフェースがES6のPromiseとfor-ofで回す新しいIteratorとTypedArrayで実装されていたので、今後ブラウザに増える新しいAPIがES6前提で作られるなら普段からES6で書くようにしたほうがいいかなと思った。個人的にはcoffeeの方がES6よりちょっと好き。for-of文がES6で新しく増えたMapやIteratorを使う時に重要なんだけど、coffeeのfor-of文は別の意味があるので、coffeeからES6のAPIを使うのは辛そうな気がしている。一応IteratorはforEachで回せるけどES6の機能メモ(coffeeとの比較みたいな感想入り)Promise非同期処理の新しいインタフェース。ScalaのFutureみたいなやつ。入れ替えもできるclass構文があるextendsとかもできる。部分的にrequireできる。これは8bit超えてるので代入されない。Generatorなど多くの機能をサポートしてる--harmonyオプションを付ければもっと色々使える--harmony_rest_parametersや--harmony_arrow_functionsなども必要に応じてONにできるサーバーで実行するならiojsで良さそう。errorになるNode0.10でもfor-of文が動かせるbabel-nodebabel付属の実行コマンドes6を直接実行できるNode0.10でもfor-of文が動かせるosascriptMacのAppleScript実行コマンドだったが、YosemiteでJavaScriptでも書けるようになった。ES6が一部サポートされている。operatorとMapとSetが動く。0.10でもiteraotr系以外動くJSが作れるES6でライブラリを書いてnpmに公開するとかにオススメ新し目のブラウザでの実行もbabelで良さそうtraceures6をes5に変換Google製Browserify+babelifyes6からブラウザjsに変換、requireを辿って1ファイルに固めてくれるのでnode_modulesも読み込めるlintESLint+babel-eslintes6をlintできるES6を実際使うES6は各ブラウザでもサポートしている機能としてない機能がバラバラなのでbabelでES5に変換してやるのが良いようだ。0.10だと動かない。あとProxyはFirefoxでしか動かないっぽい。試した感じ、例えばES6で書いてbabelで変換してからNodeのライブラリとしてnpmで配布する時はfor-ofだけ使わないように意識すれば事故は起こらないはず。(MapやTypedArrayみたいな新しい組み込み型は使わないとして)ES6と変換後のES5の動作をブラウザでも手軽に確かめたかったので、ちょっとしたツールを作った。shokaiPromiseもコールバックも使ってないのにDispatcherのwaitForで順番の制御ができる。いう事なのか気になったので調べた。npmというFacebookの中の人によるfluxアーキテクチャの説明とDispatcherが一つだけ入っているnpmを見ていた。Dispatcherは使ってみた感じ、イベント名が無いEventEmitterみたいな感じで、登録順に実行される。{"foo":"bar"}waitFor([id...])なんかwaitForにregisterメソッドから返ってくるIDを渡すと、そのコールバック呼び出しの順序を制御できるらしい。