0

HerokuのHubotをProcess Schedulerで寝かす前に報告させる



HerokuのHubotを寝させる

無料で使うには1日6時間寝かせないとならないので
Heroku | Heroku’s Free (as in beer) Dynos

dashboard.heroku.comからaddonにProcess Schedulerを追加して6時間寝させる。


参考:HerokuでHubotを指定の時間に寝かせる – はらへり日記


寝る前に報告させる

寝る前に「寝ます」とか「寝ましょう」とか言ってくれた方が安心感がある。

herokuはプロセスの終了時にSIGTERMを投げてくるので、それを受ければいい。

nodeだとprocess.on(‘SIGTERM’, function(){ });でキャッチできるはずだけどHubotではできなかった。ソースをよく見たらbin/hubotが先にSIGTERMにイベントを登録して、その中でexitしていた。なのでSIGTERMイベントを上書きした。

module.exports = (robot) ->

## 起きた時、slack-adapterがつながるのを待って通知
cid = setInterval ->
return if typeof robot?.send isnt 'function'
robot.send {room: "#general"}, "ガバリ"
clearInterval cid
, 1000

## 寝た時、通知してからexitする
on_sigterm = ->
robot.send {room: "#general"}, 'スヤリ'
setTimeout process.exit, 1000

if process._events.SIGTERM?
process._events.SIGTERM = on_sigterm
else
process.on 'SIGTERM', on_sigterm

processがイベント管理に使っているEventEmitterは先に登録したイベントが先に実行される。先にbin/hubotが登録したイベントを削除するにはイベント登録時にreturnされるidを使うしか無いので、仕方なく_eventsプロパティを直接書き換えた。
hubotの仕様が変わった時に挙動がおかしくなるかもしれないけど、例えばsocket.ioがhttp.serverに/sockets/socket.io.jsを登録する処理とかでも_eventsの順序入れ替えをやっているし、まあしょうがない。EventEmitterとはそういう物だと思うしかない。

先に登録されていなければ普通にonで登録する。

本当は上書きじゃなくて先に実行されるようにしようかと思ったけど、eventemitterは登録されているコールバックが複数なら配列で持ち、1つなら配列ではなく関数を直接持つので、なんだか面倒になって上書きにした。

0

またHubotのbrainが爆発したのでhubot-mongodb-brain作った

既存のbrainがあまりにもひどいので自作した。

https://www.npmjs.com/package/hubot-mongodb-brain
https://github.com/shokai/hubot-mongodb-brain

npm installして、external-scripts.jsonに書けば使える。何も設定しなくてもローカルのmongodbか、Herokuならmongolabかmongohqを読み込む。

他のbrainからの移行スクリプトもある。


爆発

以前爆発した時
hubotのbrainが爆発した

hubot-brain-redisは全データを1つのblobとして固めて保存するから、brainのサイズが1.5MBを超えるとRedisToGoのmax memoryにひっかかって保存できなくなる。
そこでhubot-brain-redis-hashに乗り換えたのだが、やっぱり2MB超えたあたりで保存できなくなった。brain-redis-hashもよく見たら1つのblobにまとめて1keyに保存してた。READMEには1つのblobとしては保存しないって書いてあるけど、よくコード読んだら

// brainのデータ構造
{
users: userとroomのリスト
_private: { // この中をrobot.brain.get/setで操作している
key1: value1,
key2: value2,
key3: value3
(略)
}
}
これのusersと_privateを別に保存してるだけなので、全然解決してない。

_privateの中をkey毎に保存するべきで、usersはそもそも用途が無いので保存する必要がない。
hubot-mongodb-brainでは_privateだけ保存するようにした。

他の選択肢

mongo-brainとmongolab-brainも、1 documentに全部固めて保存するのでだめ。そもそもcollections.find().limit(1)とかcollections.find({})とかで取り出してるのが気持ち悪すぎる。

0

Circle CIのビルド結果をHubotで通知

久しぶりにCircle CIを試したら、起動が妙に速くなっていた(前からこんなに速かったっけ?)のでいくつかのプロジェクトで使ってみる事にした。

Slackのインテグレーションがlimitに達していたので、Hubotで通知させるのを書いた。

circleci-webhook.coffee


設定

こんな感じでwebhook設定するとJSONが来るので、HubotがSlackに通知してくれる。

circle.yml
machine:
node:
version: 0.12
deployment:
staging:
branch: master
heroku:
appname: (herokuのアプリ名)
notify:
webhooks:
- url: https://自分のhubot.com/circleci-webhook?room=(chat部屋名)

動作

Hubot自体のビルド通知も、自分自身にやらせてる。
CircleCIでテスト→Herokuにデプロイ→Hubot起動→CircleCIからビルド結果がWebhookで届く→HubotがSlackに通知 という順に動いている。

0

Hubotでbotを3秒で作る

Slackでボットを5秒以内に作れるツールを作った – 波打際のブログさん


単語に反応して返事するbotをめっちゃ作りたいみたいなのはすごくある。
Hubotでなんとかしてる。

準備


まずHubotをGitHubにpushしたらTravis CIでテストされて、通ったらHerokuにデプロイされるようにしておく。テストといってもcoffeelintとjsonlintしかしてないけど。

リポジトリはOrganizationに置いてあるので、メンバーならGitHubのWeb上でbotを改変できて、保存したらすぐテスト走ってデプロイされる。gitでバージョン管理されてるからrevertもできる。
もちろん手元で編集してgit pushでもいい。最近Herokuはgithubやdropboxのhookからデプロイできるようになってた気がするのでそれもいいと思う。


こういうスクリプトを書く

https://github.com/masuilab/slack-hubot/blob/master/scripts/curry_meshi.coffee

ファイルの頭のあたりに反応する単語、返事(配列か関数で書ける)、返事する確率 を書けるようになっている。

config =
カレーメシ:
hear: [
/カレー/i
/curry/i
/(おなか|ハラ|はら|腹)/i
]
reply: [
'カレーメシ!!'
'ボーキメシ!!'
'ジャッスティス!!!'
'http://www.currymeshi.com'
'http://gyazo.com/fc6c4a6f74d41ee472948c35d7ab1d45.png'
'https://www.youtube.com/watch?v=vhSBtoviSKw'
]
ratio: 0.3
いくつ:
hear: [
/いくつ/
/何個/
]
reply: (msg) ->
"#{Math.floor(Math.random()*10)+1}個でじゅうぶんですよ"
ratio: 1

ところでHerokuがfreeプランだと1日18時間しか使えなくなるそうなので、毎日6時間寝るHubot scriptほしい

0

詳しい人を教えてくれる「Hubot 教えて君」を作った

hubot-osietekunというhubot scriptを作った。

https://www.npmjs.com/package/hubot-osietekun
https://github.com/shokai/hubot-osietekun

誰に質問するべきか教えてくれる。
新参者に便利だし、他にもchat roomが複数あって見通せない時に誰が詳しいのか探せるので便利そう。


教えて

「hubot 教えて 単語」 で誰が詳しいか教えてくれる。



インストール


npm install hubot-osietekun -save

あとは普通にexternal-script.jsonに書けば読み込まれる。
外部サービスを一切使ってなくて、hubot内だけで完結してる。


実装

hubotが発言を全部kuromojiにかけて誰がどの名詞を使ったかカウントしてる。

形態素解析器kuromojiがnpmで提供されていたので使った。npmの中に辞書も入っていてrequireすればすぐ使えるのがすばらしい。おかげでherokuとかにも簡単にデプロイできる。

ただ一箇所npmjs.orgのドキュメントが間違ってて、build(function(tokenizer){ ~~ })じゃなくてbuild(function(err, tokenizer){ ~~ })だった所でちょっと詰まった。

複数単語のスコアの計算

単純に掛け算している。

複数の単語について質問した場合、例えばreactについて
shokai 5
nikezono 10
zakuni 0

で、coffeeについて
shokai 5
nikezono 2
zakuni 10

という回数だけ発言していた場合、「react coffee」については
shokai 25
nikezono 20
zakuni 0

になるので、それぞれの単語についてバランスよく言及している人のスコアが上がる。どれかがゼロ回の人は0になる。


教えます

しばらく使っていたら、教えたいという人がいたので「hubot 教えます (名詞)」で登録できるようにした。


教えたいと言った人は詳しい人のついでに推薦される。

Javaについて質問したら、keroxpが教えたいと言っていた。


拡張


教えて君の機能を拡張できる。

レスポンスの拡張


Gyazz(増井先生の作ったWiKi)のページを推薦している。これは教えて君の機能には含まれていない。hubot側で教えて君を拡張している。



“osietekun:ready”イベントの後で”response”イベントを登録しておくと拡張できる。
こんな感じ
robot.on 'osietekun:ready', (osietekun) ->

osietekun.on 'response', (msg, res) ->
if res.masters.length < 1
for word in res.words
msg.send "#{word}については http://your-great-wiki-site.com/#{word} を見るといいかも"

scripts/osietekun-gyazz.coffeeの中で書いてて、ページが存在するかとか色々チェックしてからレスポンス返してるので長くなってるけどまあこんな感じ


「教えます」の拡張

他にも、「教えます」も拡張できる。WiKiにページが無い時に書くことを依頼したりできる。


robot.on 'osietekun:ready', (osietekun) ->

osietekun.on 'register:teacher', (msg, query) ->
msg.send "http://your-great-wiki-site.com/#{query.word} に書いてもいいんだよ"