Upgrading
Contents
Upgrading to v2.0
Most applications need no code changes. The minimum Ruby version has gone up, two behaviours changed, and one new setting is worth applying deliberately.
Ruby 3.2 is now the minimum
v1.4 ran on Ruby 2.5 and later. v2.0 requires Ruby 3.2 or greater.
Who is affected. Anyone on Ruby 3.1 or earlier. Bundler will refuse to install v2.0 rather than failing at runtime, so this surfaces immediately.
What to do. Upgrade Ruby to 3.2 or later, or stay on v1.4. Every Ruby before 3.2 is now past its end of life and no longer receives security fixes.
Both CRuby and JRuby are tested, on Ruby 3.2, 3.3, 3.4 and 4.0.
#completed? no longer reports a blocked minion as finished
Previously #completed? was true for a thread that was dead or sleeping. A minion waiting on
a database call or an HTTP request therefore looked completed while it was still running, with
#failed? false and #exception nil.
It is now the exact opposite of #working?.
Who is affected. Code that used #completed? to decide whether a result was ready:
# This was acting on a result the minion had not produced yet
use(minion.result) if minion.completed? && !minion.failed?
What to do. In most cases, nothing: the new behaviour is what the code intended. If you were
relying on #completed? returning true early, that was a bug being masked. To wait for a result,
just call #result, which waits for you.
Minions now run inside the Rails executor
Under Rails, every minion now runs inside Rails.application.executor, configured by the railtie.
Reloading is held off while a minion runs, and ActiveRecord connections and the query cache are
managed the way Rails manages them during a request.
Who is affected. Rails applications. There is nothing to configure, and for most applications this only removes surprises rather than creating them.
What to do. Nothing, unless you have a reason to opt out:
ParallelMinion::Minion.executor = nil
Register any context your scoping depends on
This is not a behaviour change. It is a gap that has always existed and now has a fix, and it is worth acting on because when it bites, it fails open.
Thread local state has never crossed into a minion. Libraries whose scope is conditional on that state apply no scope at all inside a minion, so a query that is correctly scoped in the calling thread can return rows it should not.
Who is affected. Applications using ActiveSupport::CurrentAttributes, ActsAsTenant,
RequestStore, or their own Thread.current[...] for anything a query scopes on.
What to do. Register a handler at startup:
# config/initializers/parallel_minion.rb
ParallelMinion::Minion.register_context(
capture: -> { Current.attributes },
around: ->(attributes, &block) { Current.set(**attributes, &block) }
)
Note that your test suite will not tell you whether you needed this. With minions disabled the block runs inline, where the context is intact. See Carrying request context into a minion.
Rails 5.1 through 7.1 are no longer tested
Rails 7.2, 8.0 and 8.1 are tested. Rails remains optional.
New in v2.0
#timed_out?distinguishes anilreturned because the minion timed out from anilthe block itself produced. See Step 6.register_contextcarries thread local application context into a minion, described above.Minion.executorexposes the executor setting.
Fixed in v2.0
#resultnow joins the minion’s thread on every path. The join was previously skipped when the minion had already finished, which on JRuby and TruffleRuby could drop an exception raised inside the minion, so#resultreturned instead of re-raising.- The cleanup that returns ActiveRecord connections to the pool now runs with asynchronous
interrupts masked, so an
:on_timeoutexception can no longer abort it part way and return a connection to the pool mid-transaction. Minion.current_scopesis now defined unconditionally. It was previously defined only if ActiveRecord had already loaded, so an application that loaded ActiveRecord later raisedNoMethodErroron every threaded minion.