RACK_ENVとUnicorn、SinatraでのRACK_ENVの扱いと注意点

RACK_ENVについて調べた内容とUnicorn、SinatraでのRACK_ENVの扱い方や注意点をまとめました。
RACK_ENVとはRACKの環境変数です。
何を設定するかによって使用するmiddlewareが変わります。
RACK_ENVには、developmentdeploymentnoneの3種類があります。

以下がそれぞれのRACK_ENVで使われるmiddlewareです。

1
2
3
#       - development: CommonLogger, ShowExceptions, and Lint
# - deployment: CommonLogger
# - none: なし

https://github.com/rack/rack/blob/028438ffffd95ce1f6197d38c04fa5ea6a034a85/lib/rack/server.rb#L157

developmentdeploymentに該当しない場合はmiddlewareは何も使われないようです。

https://github.com/rack/rack/blob/028438ffffd95ce1f6197d38c04fa5ea6a034a85/lib/rack/server.rb#L228

ここを間違えてproductionと設定する例を時々見るのですが、productionは存在しないので、noneと同じ挙動となります。
capistrano3-unicornのソースコードを見てみると、productionを指定した場合deploymentを設定するようになっていました。

1
set :unicorn_rack_env, -> { fetch(:rails_env) == "development" ? "development" : "deployment" }

https://github.com/tablexi/capistrano3-unicorn/blob/master/lib/capistrano3/tasks/unicorn.rake#L7

unicornはちょっと挙動を変えていて、developmentdeploymentのときは ShowExceptionsとLintは読み込まないようです。

1
2
3
4
5
6
7
8
case ENV["RACK_ENV"]
when "development"
when "deployment"
middleware.delete(:ShowExceptions)
middleware.delete(:Lint)
else
return inner_app
end

https://github.com/defunkt/unicorn/blob/master/lib/unicorn.rb#L79

Sinatraの環境変数

SinatraはRACK_ENVとenvironmentという環境変数が2つありややこしいです。
基本的には、environmentを定義して使います。
異なる環境で実行したい場合、RACK_ENVを指定することができます(これが混乱のもと)。

1
2
異なる環境を走らせるには、RACK_ENV環境変数を設定します。
RACK_ENV=production ruby my_app.rb

https://github.com/sinatra/sinatra/blob/4c7d38eb1b2cc02ce51029f28e0c3c34ca12ccfd/README.ja.md#%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9Aenvironments

set :environment, :production と定義して、RACK_ENV=development ruby my_app.rb を実行してみました。
このときの settings.production?の戻り値は何になるでしょうか。
trueとなり、productionと判定されます。
set :environmentで指定されたもので判定されるようです。

まとめると以下のような挙動になります。

  • set :environment が指定されているときは指定された値が使われる
  • set :environment が指定されていないときは RACK_ENVが使われる
  • set :environment も RACK_ENVも指定されていないときは developmentになる

ここで1つ気になることがでてきました。
capistrano3-unicornを使った場合は、RACK_ENVはdeploymentが指定されます。
Sinatraで set :environment を設定しなかった場合はRACK_ENVの値が優先されます。
ということは、本番環境でもsettings.production?がfalseとなってしまいます。
これは意図しない挙動ですね。
また、テンプレートのキャッシュについても効かなくなってしまいます。

まとめ

Sinatraではset :environment を明示的に指定しましょう。

1
set :environment, ENV["RACK_ENV"] == "deployment"? :production : ENV["RACK_ENV"].to_sym

参考文献