Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: GoodJobをRailsアプリケーションと同一プロセスで実行するメモ📝

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便利!