Heroku等で運用しているとバッチサーバーを別のプロセスで実行するとお金が掛かったりするのでGoodJobを用いている場合にRailsアプリケーションと同一プロセスで起動する方法をメモ📝
GoodJobについてはこちら
madogiwa0124.hatenablog.com
やり方としては簡単で以下のようにgood_job.execution_mode
を:async
に変更するだけで大丈夫だった。
frozen_string_literal: true
Rails.application.configure do
config.good_job.queues = "*"
- config.good_job.execution_mode = :external
+ config.good_job.execution_mode = :async
config.good_job.cleanup_preserved_jobs_before_seconds_ago = 1.hour.to_i
config.good_job.max_threads = 2
end
以下の通りexecution_mode
を:async
に設定するとRailsのアプリケーションプロセス内の別スレッドとして動作させることができるようです。また、consoleやmigration等で起動された場合には動作しないようになっているのもありがたいですね🙏
execution_mode
(symbol) specifies how and where jobs should be executed. You can also set this with the environment variable GOOD_JOB_EXECUTION_MODE
. It can be any one of:
:async
(or :async_server
) executes jobs in separate threads within the Rails web server process (bundle exec rails server
). It can be more economical for small workloads because you don’t need a separate machine or environment for running your jobs, but if your web server is under heavy load or your jobs require a lot of resources, you should choose :external
instead. When not in the Rails web server, jobs will execute in :external
mode to ensure jobs are not executed within rails console
, rails db:migrate
, rails assets:prepare
, etc.
https://github.com/bensheldon/good_job/blob/3933005203f8781d5937e8541256488eee47380f/README.md#configuration-options
コードを軽く読んでみた限りですが、execution_mode
を:async
の場合にはRailsアプリケーションが起動されたタイミング(config.after_initialize
)でGoodJob._start_async_adapters
が実行され、Railsアプリケーション内にGoodJobの各種機能が有効化され実行が開始され、
initializer "good_job.start_async" do
config.after_initialize do
ActiveSupport.on_load(:active_record) do
ActiveSupport.on_load(:active_job) do
GoodJob._framework_ready = true
GoodJob._start_async_adapters
end
GoodJob._start_async_adapters
end
GoodJob._start_async_adapters
end
end
end
https://github.com/bensheldon/good_job/blob/3933005203f8781d5937e8541256488eee47380f/lib/good_job/engine.rb#L51-L70
エンキューされたタイミングで別スレッドを作って非同期で処理するようにしているようです。
def enqueue_at(active_job, timestamp)
executed_locally = execute_async? && @capsule&.create_thread(execution.job_state)
Notifier.notify(execution.job_state) if !executed_locally && send_notify?(active_job)
https://github.com/bensheldon/good_job/blob/3933005203f8781d5937e8541256488eee47380f/lib/good_job/adapter.rb#L181-L188
※cronとかもどうなるのかなと思ったけどGoodJobの各種機能が有効化されるタイミングでCronのマネージャーも有効化されるからRailsアプリケーションの中でcronも動くようだった。
Solid Queueに移行しようかなと思っていたのですが、
github.com
Solid Queueでは現時点では以下で検討されてますが、まだ同一プロセスでの実行はできないっぽいですね👀
github.com
GoodJob便利!