Rails8からデフォルトになるsolid_queueなどのgemについて、本番環境を想定したときにdatabase.ymlの書き方で少し問題に直面したので備忘録として記事にしたいと思います。
Solid系のgemについて
Rails8からデフォルトで以下のgemが設定されるようになっています。
これらは全てバックエンドのアダプターにRedisではなくデータベースを使用するように作られています。
Railsの記事やリポジトリを見ていると、今後はRedisなどのミドルウェアを使用しなくても本番環境でアプリケーションを動かせるようにしたいのかなーと思います。
それぞれのREADMEにインストール方法が書いていますが、その中でdatabase.ymlは以下のようなコードが示されています。
production:
primary: &primary_production
<<: *default
database: app_production
username: app
password: <%= ENV["APP_DATABASE_PASSWORD"] %>
queue:
<<: *primary_production
database: app_production_queue
migrations_paths: db/queue_migrate
直面した問題
本番環境においては、データベース周りの接続情報については秘匿情報のため環境変数を使用すると思います。
さらにRailsはDATABASE_URLという環境変数が設定されていれば、その内容を優先してデータベース接続を行うように作られています。
こんな感じのやつ
ENV["DATABASE_URL"] # => "postgresql://localhost/blog_development?pool=5"
なので、本番環境ではDATABASE_URLに値を設定してデプロイすることもあるんですが、solid系のgemではそれぞれテーブルが異なるため、例えば
- DATABASE_URL : 本体用
- DATABASE_QUEUE_URL : solid_queue用
- DATABASE_CACHE_URL : solid_cache用
- DATABASE_CABLE_URL : solid_cable用
のように4つの環境変数を設定したほうがいいのか、もしくはREADMEのサンプルのようにパスワード、エンドポイントなどを環境変数にしてDATABASE_URLを使わないほうがいいのか悩みました。
ただ、個人的に環境変数が多いと運用コストがかかるし、基本的にはテーブル名はapp_production_queueなどのように末尾が異なるケースが多いと思ったので、DATABASE_URLだけで何とかできないかと考えました。
解決方法
最終的にdatabase.ymlを以下のコードにしました。
production:
primary: &primary_production
<<: *default
url: <%= ENV["DATABASE_URL"] %>
cache:
<<: *primary_production
url: <%= ENV["DATABASE_URL"]&.+("_cache") %>
migrations_paths: db/cache_migrate
queue:
<<: *primary_production
url: <%= ENV["DATABASE_URL"]&.+("_queue") %>
migrations_paths: db/queue_migrate
cable:
<<: *primary_production
url: <%= ENV["DATABASE_URL"]&.+("_cable") %>
migrations_paths: db/cable_migrate
urlを使うことで、環境変数にDATABASE_URLが指定されていても上書きされます。
そしてdatabase.yml内で明示的にENV[“DATABASE_URL”]を使うことで、solid系の指定は文字列の結合という形にしました。
これであれば、管理すべき環境変数はこれまで通りDATABASE_URLだけなので簡単です。
ちなみに、&. とnilガードにしているのはdevelopment環境などでもdatabase.ymlは読み込まれるので、エラーにならないようにするためです。
他にも良い方法があるかもしれませんが、環境変数の管理を最小限にするには良い方法ではないでしょうか。
スポンサーリンク