データベースなしで Rake assets:precompile を実行

rake assets:precompile タスクにはデータベース接続が必要であることに気づきました。つまり、このタスクは「ビルド時」(コンテナイメージの構築中)ではなく、「実行時」(デプロイ後)にのみ実行可能です。このタスクは実行時間が非常に長くかかるため、不便です。

私は Ruby/Rails 開発者ではないため、調査を行ったところ、この動作は Rails 4 まで 無効化可能 であり、それ以降は開発者たちがいくつかのハック(null データベース接続など)に頼っていることがわかりました。後者の場合、何らかの障害を起こさないようにするため、アプリケーションの内部構造についての深い知識が必要です。

より良い解決策を探している最中に、このコミット を発見しました。これは精神面で類似しているようです。そこで以下の質問があります:

  • すでに開発者がこの問題に取り組んでいるのでしょうか、それとも技術的な理由で実施不可能なのでしょうか?
  • タスクの一部が実際にデータベース接続を必要とする場合、タスクを 2 つ(またはそれ以上)に分割して、ロケールのコンパイルや JS/CSS の最小化などの作業をビルド時に行うことは可能でしょうか?
  • 現時点で既知の回避策(上記の「null データベース」など)は存在しますか?

テーマはデータベースに保存されます(管理UIで編集されます)。そのため、CSSはPostgreSQL内に格納されており、それらをプリコンパイルするにはビルド時にデータベース接続が必要です。

情報ありがとうございます!

ロケールのビルドを別々に実装し、ビルド時に実行することは可能でしょうか?
また、いくつかの環境(少なくとも私の環境ではそうなのですが)ではテーマの変更を許可したくない場合もあるかもしれません。その場合、CSS の代替ストレージを提供することは可能でしょうか?

カスタマイズ UI 全体を無効化するスイッチを導入するアイデアについては、すでに議論しました。これにより、CSS ファイルをビルド時にコンパイルし、ビルド中にオブジェクトストレージへアップロードすることが可能になります(JS コアやプラグインと同様の仕組みです)。

しかし、これは非常にニッチなケースであり、エンタープライズ向けデプロイメントのみに関心がある一方で、ウェブ上のコミュニティの 99% には何の価値ももたらしません。そのため、この機能はロードマップに含まれておらず、新機能の開発やパフォーマンス改善にリソースを割くことと比較すると、実現へのハードルは非常に高いです。

貴社の環境やユースケースについて、もう少し詳しく教えていただけますか?

すでにそのアイデアが議論されていたと知り、安心しました。変更に伴う作業量が大きすぎて、正当化できないことも理解しています。

私の場合、Discourse は既存の Web サイトと連携するため、Web サイトのデザインに合わせた固定のカスタムテーマを使用します。そのため、動的に変更することは意味がありません。

ああ、ビルド時にデータベースに接続できないというユースケースのことでした。

ええと、イメージをビルドするときは開発用のノートパソコンで作業しています。その後、そのイメージをリポジトリにプッシュし、最終的なシステム(DigitalOcean の VPS)がそこからプルします。

データベースは VPS 上のボリュームに存在するため、私のノートパソコンで更新することはできません。そのためには、Discourse を停止し、データベースをノートパソコンに rsync で転送し、イメージをビルドしてプッシュし、最後に Discourse を再起動する必要があります…

つまり、データベースとアプリケーションを同じ Droplet 内で実行しているのですね?

その場合、公式インストールガイドに従って、アプリケーションとデータベースが同じ Droplet 内に配置される構成にすれば、完全に機能するサイトが構築できます。このサイトは、Web インターフェースから、あるいは必要に応じてコマンドラインからフルイメージの再構築を行って更新することができます。

「ホスト上に直接」という意味であれば、いいえです。これらはコンテナ、具体的には podman コンテナ内で実行されています。理想的には、コンテナを複数のものに分けたいと考えています(Discourse用、Postgres用、Redis用など)。しかし、これは現在議論している問題と関連しており、適切な対応策についてまだ確信が持てていません。

私には危険に思えます。私は通常、本番環境にデプロイする前に開発環境でコンテナをテストします。さらに、理想的にはコンテナは読み取り専用であるべきです。

それらのコンテナを分割し、別の短期間のドロレットでイメージのブートストラップ処理を実行することができます。ドロレットは時間課金なので、コストは安く済みます。さらに、データベースコンテナホストと「ビルド」コンテナホストの間で、ドロレットのプライベートネットワークを活用することも可能です。

へへ、アイデアをありがとうございます。ただ、それは次第に複雑になってきます。さらに、ディスコースを停止してブートストラップ処理を待つ必要があるため、問題の解決にはなりません。そうしないと、データが不整合になる可能性があります。

アップグレード時には長いダウンタイム(マイグレーションとプリコンパイルで 5〜6 分)を覚悟する必要がありそうです。それでも、もし可能であれば、このトピックへのリンクを付けて、トラッカーに低優先度のissueとして登録していただけると幸いです。

ありがとうございます。これからも素晴らしい仕事を続けてください!

いいえ、そうではありません。

5〜6 分に対して「数秒」であるべきですが、専用のデータコンテナと Web コンテナが必要です。何を優先するかによります。

また、ベンチマークによると、高速なサーバー での再構築は約 3 分です。

なるほど、ありがとうございます。この場合、コンテナを分割します。そもそも、こちらの方がアーキテクチャとして優れています。

ただし、なぜこれで違いが出るのかがよくわかりません。私の認識が間違っていなければ、すべてのコンテナはすべてのホスト CPU を共有します(設定で変更しない限り)。そのため、どちらの場合でもプロセスは並列に実行されるはずです。何か見落としているのでしょうか?

新しいコンテナの起動中に、古いコンテナは稼働したままになります。その後、古いコンテナを素早く停止して新しいコンテナを開始できるため、ダウンタイムを短く抑えることができます。