Rack-traffic-signalというgemを公開しました

Qiitaにも同じ記事を書いてます

どんなgem?

Ruby製Webアプリケーションにメンテナンスモードを導入するためのRackミドルウェアです。

↓みたいなやつです。

特長

すでにメンテナンスモードを導入するためのgemにはrack-maintenanceなどがありますが、このrack-traffic-signalには次のような特長があります。

メンテナンスグループごとのメンテナンスモード制御

パス、HTTPメソッドの組み合わせを「メンテナンスグループ」というくくりで扱います。

特定のメンテナンスグループだけをメンテナンスモードに入れる/外すことができます。新規ユーザー登録機能(get: /users/new, post: /users)のみメンテナンスモードに入れるといったことができます。 メンテナンスグループはリソースとアクションの組み合わせで設定できます。たとえばさきほど例に上げた新規ユーザー登録機能はリソース: user, アクション: registerと設定できます。

メンテナンスグループごとのレスポンス設定

メンテナンスグループごとに、メンテナンスモード時のHTTPステータスコード、レスポンス本文を設定することが可能です。

APIに対してはJSON形式で、それ以外はメンテナンス告知HTMLを返す、まだ一般公開したくない機能に関しては社内IPからのアクセスのみ通しそれ以外は404を返すなど柔軟な設定が可能です。

使用法

インストール方法などはREADMEを参照してください。ここでは、一応READMEにのっているものの分かりづらいだろうなぁという設定ファイルの書き方について解説します。

設定の書き方

Rack::TrafficSignal.setup do |config|
  # internal_ips に含めたIPアドレスは、社内IPアドレスとして扱えます。
  # 社内IPアドレスからのアクセスかどうかを判別するメソッドが存在しており、
  # その場合はメンテナンスモードをスキップする、といった制御が可能です。
  # その例は config.skip_by を参照してください。
  config.internal_ips = ['192.168.1.1/25']

  # メンテナンスモードをスキップするパスを指定。
  # こちらも `internal_ips` と同様 `skip_by` ブロックの中で利用することを想定しています。
  config.skip_paths = [/^\/users\/12345/]

  # メンテナンスグループに固有のレスポンス設定を書かなかった場合に使われる設定
  config.default_status = 503
  config.default_content_type = 'application/json'
  config.default_body = { error: 'error' }.to_json

  # メンテナンスグループの設定を行います。
  # パスの設定は文字列・正規表現どちらでも行なえますが、基本的には正規表現を用います。
  # 文字列で設定した場合は、厳密に一致した場合しか適用されません。
  config.maintenance_group =   {
    # <resource>: {
    #   <action>: [
    #     { methods: [:get, :post], path: <path_to_maintenance>}
    #   ]
    # }
    users: {
      register: [
        { methods: [:get], path: "/users/new"},
        { methods: [:post], path: "/users" }
      ],
      # また、メンテナンスグループごとにHTTPレスポンスステータスコードやレスポンスボディを
      # 設定することも可能です。
      update: [
        { methods: [:put], path: %r{/users/\d+}, status: 404, body: { meta: '404'}.to_json }
      ]
    }
  }

  # 現在のアプリケーションのメンテナンスモードを返すブロックを渡します。
  # 結果として、シンボルの配列を返すものである必要があります。
  # 基本的には `:<resource>_<action>` という形式ですが、特例があります。
  # :<resource>_all => そのリソースすべてのアクションをメンテナンスモードに入れる
  # :all => すべてのメンテナンスグループをメンテナンスモードに入れる
  config.maintenance_status_by do
    ENV['MAINTENANCE_STATUS'] # [:users_register, :users_update]
  end

  # このブロックがtrueを返した場合、メンテナンスモードかどうかの判定を行いません。
  # 次の例では、アクセス先が `skip_paths` に含まれている or 社内IPからのアクセスの場合
  # メンテナンスモードをスキップしています。
  config.skip_by do |env|
    Rack::TrafficSignal.skip_path?(env) || Rack::TrafficSignal.internal_access?
  end

  # こちらもメンテナンスモードをスキップする設定ですが、ただスキップするだけでなく
  # HTTPヘッダに 'X-RACK-TRAFFIC-SIGNAL-MAINTENANCE' が付与されます。
  # ちゃんとメンテナンスモードに入っているかどうか確認できるようになります。
  #
  # ヘッダをいちいち確認するのは面倒なので、付与されてたらみためでわかるようになる
  # ブラウザ拡張とかあったらよいですね!
  config.skip_with_warning_by do |env|
    Rack::TrafficSignal.skip_path?(env) || Rack::TrafficSignal.internal_access?
  end
end

さいごに

一週間ほどの突貫でつくったgemであり、危ないところも多々あります。 issuetたててもらったり、Pull Request送っていただけたりするととても喜びます。

https://github.com/k5trismegistus/rack-traffic-signal