ここでいう Health Check API とは
Pattern: Health Check API - Microservice Architecture
上記は一例ですが、Web アプリケーションが動作をしているかを確認できるエンドポイントを提供することを指しています。
他に呼び方があるかもしれませんが。
Rails で利用できる Gem
調査時に発見できたものです。拾うワードが少なかった印象はあります。他にもありそう。
数/last_update は 2017/6/30 時点
Gem | description | last_update | |
---|---|---|---|
ianheggie/health_check | Simple health check of Rails app for use with uptime checking sites like newrelic and pingdom | 191 | 2016/12/7 |
jbarnette/pinglish | A simple Rack middleware for checking application health. | 154 | 2016/11/28 |
sportngin/okcomputer | Provides a health-check endpoint to your Ruby on Rails apps. | 137 | 2017/5/9 |
lbeder/health-monitor-rails | A Rails plugin which provides a health checking and monitoring API of various services and application aspects. | 58 | 2017/6/21 |
mitaku/komachi_heartbeat | Rails アプリケーションとDBサーバーの死活監視するためのURLを提供するEngine | 39 | 2017/5/22 |
lserman/aws-healthcheck | Mounts a 200 response at /healthcheck for AWS load balancers | 14 | 2016/10/31 |
on-site/server_health_check on-site/server_health_check-rack on-site/server_health_check-rails |
This gem provides a standard set of health checks for web services | 0 | 2017/5/8 |
Rack / Rails Mountable Engine などの違いはありつつも、いずれもあるエンドポイント(大抵は変更可能)に対してリクエストをした際に DB 等(大抵は Migration 管理用のテーブル)にアクセスして、動作確認をし、成功すれば 200 を返すという単純なものです。
それぞれで、ビルトインのチェック処理が異なるので、どれぐらいカスタマイズしたいかや、「面倒だからビルトインが多いほうがいい」等で決めれば良いかと思います。
okcomputer について
私のチームでは okcomputer
を選定しました。
ianheggie/health_check, lbeder/health-monitor-rails との比較で悩みましたが、ビルトインのチェックの多さと、 の場合にもメッセージを返却できる点で sportngin/okcomputer を選びました。
他は、Rails5 リリース以降にメンテナンスが行われていない事や、 が少なすぎる等で一時除外しました。ただ、komachi_heartbeat だけは、選定が終わってから見つけたのでなんとも言えないです。
使い方
README が丁寧にかかれているので特に迷うことは無いと思います。
最も簡単な例であれば Gemfile
に追加しただけで以下にリクエストすればチェックが行われます。
/okcomputer
/okcomputer/all
/okcomputer/default
-
/okcomputer/database
- database チェックだけ個別に行いたければこちら
/okcomputer
以外は、.json
をつければ JSON フォーマットで返されます。
% curl http://localhost:3000/okcomputer/default
default: PASSED Application is running (0s)%
% curl http://localhost:3000/okcomputer/default.json
{"default":{"message":"Application is running","success":true,"time":9.889001375995576e-06}}
見ての通りで成功時でも message
を返せるため、単純に boolean の結果としてだけでなく、アプリの内部状態を知るための情報を返させてもいいかもしれません。
okcomputer の Collection 機能を使う
README には記述されていませんが、Collection という機能が存在します。(なくなる予定なのかもしれません)
チェックの登録時に collection 名が渡せる
okcomputer ではチェックの登録に以下のように Registry
を使います。
OkComputer::Registry.register "database", OkComputer::ActiveRecordCheck.new
Registry#register
は以下のようになっています。
module OkComputer
class Registry
# Public: Register the given check with OkComputer
#
# check_name - The name of the check to retrieve
# check_object - Instance of Checker to register
# collection_name - The name of the check collection the check should be registered to
def self.register(check_name, check_object, collection_name=nil)
check_object.registrant_name = check_name
find_collection(collection_name).register(check_name, check_object)
end
private_class_method def self.find_collection(collection_name=nil)
collection_name ? default_collection.fetch(collection_name) : default_collection
rescue KeyError
raise CollectionNotFound
end
def self.default_collection
@default_collection ||= CheckCollection.new('Default Collection')
end
#register
は collection_name
という引数があり、それを使って default_collection
から fetch
をしているように見えます。
そして default_collection
は CheckCollection
のインスタンスであることがわかります。
続いて、CheckCollection
を見ていきます。
module OkComputer
class CheckCollection
def initialize(display)
self.display = display
self.collection = {}
end
# Public: Returns a check or collection if it's in the check collection
#
# key - a check or collection name
# throws a KeyError when the key is not found
def fetch(key, default=nil)
found_in = self_and_sub_collections.detect{ |c| c[key] }
raise KeyError unless found_in
found_in[key]
end
def sub_collections
checks.select{ |c| c.is_a?(CheckCollection)}
end
def checks
collection.values
end
def self_and_sub_collections
[collection] + sub_collections
end
def register(name, check)
collection[name] = check
end
CheckCollection
は内部に collection
という Hash を持つだけのようです。 #fetch
では、渡されたキーから自身が管理する collection と、自身が管理する collection の中にある sub_collections が管理する collection からも検索を行っているようです。
つまり以下のような構造で collection を管理しているようです。
OkComputer::CheckCollection.new('Default Collection')
@display = 'Default Collection'
@collection = {
'database' => OkComputer::ActiveRecordCheck.new,
'sidekiq' => OkComputer::SidekiqCheck.new,
'sub1' => OkComputer::CheckCollection.new('sub1') # この中でもさらに collection がある
}
再帰的に fetch
するわけではなさそうなので、おそらく第一階層の sub 階層までになりそうです。
よって、Registry#register
の際に collection_name
を渡すと、 Default 以外の collection にチェックを登録することができます。
そして Default 以外の collection は、単に CheckCollection
を Registry#register
すれがいいことがわかります。
Collection を追加する
ここまで分かると独自に collection を追加できます。
OkComputer::Registry.register "special_check", OkComputer::CheckCollection.new('Special Check Collection')
collection を追加できれば、この collection にチェックを追加しましょう。
OkComputer::Registry.register "migration", OkComputer::ActiveRecordMigrationsCheck.new, "special_check"
こうすると以下の URL でチェックができます。
% curl http://localhost:3000/okcomputer/special_check
% curl http://localhost:3000/okcomputer/migration
# 以下は駄目
% curl http://localhost:3000/okcomputer/special_check/migration
所属する Collection が異なるので以下のように default で呼び出しても migaration
チェックは実行されません。
# 以下の結果に migration の結果は含まれない
% curl http://localhost:3000/okcomputer/default
Collection の用途
okcomputer
はもちろん単純な Health Check 用途に使った方がいいですが、Collection を分けておくことで、監視のエンドポイントを分けられたり、メトリクス用にチェックを作る時に、うまくグルーピングができて便利です。
参考
2 年以上前ですが、ドリコムさんは komachi_heartbeat
を利用していると書かれています。
Mountable Engine だらけの Rails アプリ開発 - http://blog.onk.ninja/
Gitlab は health_check
を使っているようです。
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/Gemfile#L382