lib/good_job/railtie.rb in good_job-2.9.0 vs lib/good_job/railtie.rb in good_job-2.9.1
- old
+ new
@@ -32,11 +32,30 @@
GoodJob.retry_on_unhandled_error = rails_config[:retry_on_unhandled_error] if rails_config.key?(:retry_on_unhandled_error)
end
end
initializer "good_job.start_async" do
+ # This hooks into the hookable places during Rails boot, which is unfortunately not Rails.application.initialized?
+ # If an Adapter is initialized during boot, we want to want to start its async executors once the framework dependencies have loaded.
+ # When exactly that happens is out of our control because gems or application code may touch things earlier than expected.
+ # For example, as of Rails 6.1, if an ActiveRecord model is touched during boot, that triggers ActiveRecord to load,
+ # which touches DestroyAssociationAsyncJob, which loads ActiveJob, which may initialize a GoodJob::Adapter, all of which
+ # happens _before_ ActiveRecord finishes loading. GoodJob will deadlock if an async executor is started in the middle of
+ # ActiveRecord loading.
+
config.after_initialize do
- GoodJob::Adapter.instances.each(&:start_async)
+ ActiveSupport.on_load(:active_record) do
+ GoodJob._active_record_loaded = true
+ GoodJob.start_async_adapters
+ end
+
+ ActiveSupport.on_load(:active_job) do
+ GoodJob._active_job_loaded = true
+ GoodJob.start_async_adapters
+ end
+
+ GoodJob._rails_after_initialize_hook_called = true
+ GoodJob.start_async_adapters
end
end
end
end