Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
delayed (2.0.3)
delayed (2.1.0)
activerecord (>= 6.0)
concurrent-ruby

Expand Down
42 changes: 31 additions & 11 deletions lib/delayed/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,37 @@

next unless defined?(Rails.application.config)

# By default, Rails < 6.1 overrides eager_load to 'false' inside of rake tasks, which is not ideal in production environments.
# Additionally, the classic Rails autoloader is not threadsafe, so we do not want any autoloading after we start the worker.
# While the zeitwork autoloader technically does not need this workaround, we will still eager load for consistency's sake.
# We will use the cache_classes config as a proxy for determining if we should eager load before booting workers.
if !Rails.application.config.respond_to?(:rake_eager_load) && Rails.application.config.cache_classes
Rails.application.config.eager_load = true
Rails::Application::Finisher.initializers
.find { |i| i.name == :eager_load! }
.bind(Rails.application)
.run
end
# By default, Rails wants to disable eager loading inside of `rake`
# commands, even if `eager_load` is set to true. This is done to speed up
# the boot time of rake tasks that don't need the entire application loaded.
#
# The problem is that long-lived processes like `delayed` **do** want to
# eager load the application before spawning any threads or forks.
# (Especially if in a production environment where we want full load-order
# parity with the `rails server` processes!)
#
# When a Rails app boots, it chooses whether to eager load based on its
# `eager_load` config and whether or not it was initiated by a `rake`
# command. If it did eager load, we don't want to eager load again, but if
# it was initiated by a `rake` command, it sets `eager_load` to false before
# the point at which `delayed` starts setting up _its_ rake environment.
#
# So we cannot rely on that config to know whether or not to eager load --
# instead we must make an inference:
# - Newer rails versions (~7.0+) have a `config.rake_eager_load` option,
# which tells us whether the app has already eager loaded in a `rake`
# context.
# - If `rake_eager_loading` is not defined or `false`, we will then check
# `cache_classes` & explicitly eager load if true.

eager_loaded = Rails.application.config.respond_to?(:rake_eager_load) && Rails.application.config.rake_eager_load
next if eager_loaded || !Rails.application.config.cache_classes

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does !Rails.application.config.cache_classes check for? My understanding is it skips eager loading in development (where cache_classes = false) since classes reload anyway. Is that correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah -- if cache_classes == false, I use that as a signal to skip eager loading.

In newer rails versions, cache_classes is equivalent to !enable_reloading. So line 37 could be read as:

next if eager_loaded || Rails.application.config.enable_reloading

So if you've already enabled dynamic reloading, then we infer that you aren't in an environment where you care about deterministic load order in general.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, thanks!


Rails.application.config.eager_load = true
Rails::Application::Finisher.initializers
.find { |i| i.name == :eager_load! }
.bind(Rails.application)
.run
end

desc 'start a delayed worker'
Expand Down
2 changes: 1 addition & 1 deletion lib/delayed/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Delayed
VERSION = '2.0.3'
VERSION = '2.1.0'
end