Help us understand the problem. What is going on with this article?

RailsアプリケーションのデータをHubotを介してSlackに通知させる

More than 3 years have passed since last update.

つくったもの

Railsで開発しているアプリケーションのデータ、例えば日次・週次・月次の新規会員登録数のような値を、チャットボットを介してSlackに通知する仕組みを導入した。今までは同様の数値を管理画面のダッシュボードに表示していたが、チーム全員が毎日見るものなので、チャットボットに毎朝つぶやかせるようにした。

動作環境

  • Amazon Linux AMI release 2016.03
  • Rails 4.2.4
  • Node.js 0.10.46
  • Hubot 2.19.0

実装内容

RailsからDBのデータを出力

最も単純な方法として、Hubotがデータベースへ直接アクセスしてデータを取得することが考えられるが、複雑な条件で取得したい場合にはSQLの作成が面倒。Rails側にはモデルがあるのでこれを利用したい。今回はRakeタスクでデータ取得タスクを作成し、Hubotがこれを実行するようにする。

lib/tasks/report.rake
namespace :report do
  task :yesterday => :environment do
    message = <<-"EOS"
ユーザー登録数:#{User.yesterday.count}
記事投稿数:#{Post.yesterday.count}
コメント数:#{Comment.yesterday.count}
    EOS
    puts message
  end
end
app/models/user.rb
class User < ActiveRecord::Base
  include Reportable
end
app/models/concerns/reportable.rb
module Reportable
  extend ActiveSupport::Concern

  included do
    # 昨日作成されたレコード
    scope :yesterday, -> do
      range = Time.yesterday.beginning_of_day .. Time.yesterday.end_of_day
      where(created_at: range)
    end
  end
end

ここでは「昨日作成されたレコード」を表す条件をconcernにまとめて、これを利用する各モデルでincludeしている。この辺りはアプリケーションに合わせてご自由に。今回はyesterdayだけだが、先週とか先月とか条件が増えていった場合、動的にメソッド生成できたら良さそう。

HubotでRailsからデータを取得

たとえばボットに対して”report”というメッセージが送られてきた時に、レポーティングを返すコマンドをHubotに実装する。child_process.execで先ほど作成したRakeタスクを実行し、標準出力にメッセージを添えて返信している。ここもボットのキャラに合わせてご自由に。

scripts/report.coffee
child_process = require 'child_process'

module.exports = (robot) ->
  robot.respond /report/i, (res) ->
    child_process.exec "cd /path/to/rails-app && rake report:yesterday RAILS_ENV=production", (error, stdout, stderr) ->
      if !error
        output = "昨日の数字をお知らせします!\r\n"+stdout
        res.reply output
      else
        res.reply 'error'

この段階で、ボットは我々の"report"という呼びかけに対してレポーティングをしてくれるようになった。

Hubotでレポートを定期投稿

実際の運用では、我々がボットに呼びかけた時だけでなく、自動で定期的にレポートを投稿してもらいたい。ここでは"cron"というパッケージを利用する。下記記事が参考になった。
http://qiita.com/kon_yu/items/ff884d81f9c1db9b574b

投稿するタイミングの指定は通常のcrontabと同じ。ここでは平日の9:30に投稿するようにした。Railsからレポートを取得する部分は前節のコードと同じ。

scripts/cron.coffee
cronJob = require('cron').CronJob
child_process = require 'child_process'
channel_id = '*********'

module.exports = (robot) ->
  new cronJob('30 9 * * 1-5', () ->
    child_process.exec "cd /path/to/rails-app && rake report:yesterday RAILS_ENV=production", (error, stdout, stderr) ->
      if !error
        output = "昨日の数字をお知らせします!\r\n"+stdout
        robot.send {room: channel_id}, output
      else
        robot.send {room: channel_id}, 'error'
  ).start()

注意点がひとつ。SlackのAPIのバージョンアップによって、投稿するroomを指定する際は、channel名ではなくIDを渡すようになったらしい。下記URLから予め目的のchannel IDを調べておく必要がある。
https://api.slack.com/methods/channels.list

感想

ボットに投稿させることによってチーム全員が同時に数字を見ることになるので、ダッシュボードに比べてその数字についての議論が生まれやすいと思う。

今回はHubotが能動的にデータを取得してレポーティングする仕組みを構築したが、Railsで特定のDB操作があった時(問い合わせが送信されたときなど)にリアルタイムで通知できる仕組みを考えたい。

tfujiwar
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away