読者です 読者をやめる 読者になる 読者になる

MANA-DOT

PIXEL ART, PROGRAMING, ETC.

HubotでHubotの更新をforeverを利用してHubotにさせてみる

hubot

前の記事でHubotでIRCbot Consoleと同等の仕事をさせられることが分かったので、会社で置き換えて使っています。

botが色々できるようになったのですが、唯一劣ってしまった点として、スクリプトの更新の容易さがあります。IRCbot ConsoleではWebからスクリプトを編集すれば即時で反映されたのに、Hubotではローカルでソース編集したあとにgitにコミット、サーバーにログインしてpullしてHubotを再起動という、やや面倒な手順を踏む必要があります。

今日はこれをちょっとどうにかしてみました。

イデア

Hubotはなんでもできるんだから、Hubotに更新させればいいんじゃね?ってこと。 Hubotに「(bot名) update」と話しかけたら自分でgit pullして自分で再起動するのを目指します。

更新用スクリプト

公式にupdate.coffeeというのがあるため、これを参考にします。というかファイル更新するだけならこれを入れるだけでほとんど完成です。

しかし、このスクリプトではファイルが更新されるだけなので、スクリプト内にもあるように、botを手動でkillして再起動してあげなければbot自身は更新されません。まだめんどくさい。

forever の自動再起動に頼ってみる

ところで、Hubotをデーモン化するのにforever を使っています(世間ではpm2のがいいという記事もちらほら見かけますが、botには必要無いように思えたのでこっち使っています)。 foreverに関してはこちらが詳しいです。

こいつは、start, stopなどのコマンドを提供して簡単にnodeのスクリプトをデーモン化してくれますが、その他にスクリプトが終了したら自動で再起動してくれるという機能があります。

この機能に頼りきって、ファイルが更新された場合、そのままHubotには自殺してもらうことにしました。すると、foreverがHubotを再起動してくれるので、無事botが更新されるというわけです。

コード

結局以下の様なスクリプトになりました。

child_process = require 'child_process'

module.exports = (robot) ->
  robot.hear /bot.*update/, (bot) ->
    try
      robot.adapter.notice bot.envelope, "updating..."
      child_process.exec 'git pull', (error, stdout, stderr) ->
        if error
          robot.adapter.notice bot.envelope, "git pull failed: " + stderr
        else
          output = stdout+''
          if not /Already up\-to\-date/.test output
            robot.adapter.notice bot.envelope, "botが更新されました: " + output
            robot.adapter.notice bot.envelope, "再起動します"
            process.exit()
          else
            robot.adapter.notice bot.envelope, "botは最新です"
    catch e
      robot.adapter.notice bot.envelope, "git pull failed:" + e

といっても、update.coffeeからnpmのアップデートなど、今回必要ない機能を省き、メッセージを適当に変えてファイル更新された場合は process.exit() するようにしただけです。

また、foreverを利用した起動スクリプトは以下のような感じになりました。

#!/bin/sh

PATH=/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
export HUBOT_IRC_NICK="mana_bot"
export HUBOT_IRC_ROOMS="#mana_bot"
export HUBOT_IRC_SERVER="manaten.net"

case $1 in
    "start" | "stop" | "restart" )
       ./node_modules/forever/bin/forever $1 \
           -p /var/run/forever \
           --pidfile /var/run/mana_bot.pid \
           -l /var/log/mana_bot.log -a \
           -c coffee node_modules/hubot/bin/hubot --adapter irc
    ;;
    * ) echo "usage: manabot.sh start|stop|retart" ;;
esac

これで、あとはforeverがbotを再起動してくれ、botが最新の状態になります。めでたしめでたし。

もっとスマートな方法があれば教えて欲しかったり。