Rails 6 rc2 makes parallel testing a framework concern
Rails 6 reaches its second release candidate with process and thread based test parallelism. Separate worker databases solve one part of isolation, while external resources still need explicit ownership.
A test suite can have enough independent work to use several processors while still assuming that every test owns the same database. Parallel execution makes that assumption visible. Rails 6.0.0 rc2, released July 30, brings the framework close to final release with its parallel testing support among the major changes under evaluation.
The announcement says blockers discovered during rc1 have been cleared. It proposes a final release in a couple of weeks if no major new issue appears. That is the status of a release candidate, not a statement that the final version has already shipped. The concrete opportunity is to exercise application behavior against the candidate's implementation.
I find Ruby's collection and block syntax useful for expressing work clearly. Test execution introduces another requirement, which is keeping independent examples independent when their execution overlaps. Rails 6 addresses some of that coordination inside the framework, where database setup can follow the worker lifecycle.
Processes are the default isolation boundary
The testing guide in the rc2 sources describes process-based execution as the default parallelization method. It uses Ruby's DRb system and forks the configured number of worker processes. Thread-based execution is also available, so the two models need to be distinguished.
A basic configuration chooses a fixed worker count in the test helper.
class ActiveSupport::TestCase
parallelize(workers: 2)
end
Active Record creates and loads a separate test database for each process. The worker number becomes a suffix on the database name. A run with one worker or fewer does not fork and uses the ordinary test database. Those behaviors make the worker count part of the execution environment rather than simply a hint to a scheduler.
The database separation preserves an important assumption. One test process can change its test records without another process observing those changes through the same database. The framework can arrange that separation because it already owns the connection configuration and schema-loading workflow.
It does not follow that every side effect becomes private. A test may write a fixed filename or contact a service whose state all workers share. Separate SQL databases do not isolate those destinations. The application's test design has to identify resources outside the database that require their own worker-specific context.
Worker lifecycle hooks support additional resources
The process implementation supplies parallelize_setup after workers fork and parallelize_teardown before they close. Both receive the worker identifier. The guide describes these hooks as useful for work that depends on the number of workers, including additional database arrangements.
The identifier can give a test resource an unambiguous owner. If two processes both use the same temporary output name, a cleanup operation in one process can remove the other process's file. A worker-specific namespace changes that relationship. The setup and teardown need to agree on the same namespace so cleanup affects only the resource that worker owns.
This is more precise than adding a delay around a failing test. A delay changes the chance of overlap without defining who owns the shared resource. Separating resources or defining coordination changes the actual contract. The worker hooks provide a place to establish that contract for resources Rails does not manage automatically.
Process teardown also matters when a test aborts partway through its intended work. Cleanup should follow resource ownership instead of assuming the successful test path executed every operation. A suite can otherwise become dependent on which example failed earlier, even when its normal successful runs appear independent.
I regard this as the more useful part of built-in parallelism. Saving elapsed time is desirable, but a documented lifecycle makes the resulting failures interpretable. A test that depends on a resource shared across workers can be corrected at the ownership boundary instead of accumulating timing adjustments.
Threads provide a different execution model
The rc2 guide documents a thread option backed by Minitest's parallel executor. A bounded configuration can request that model explicitly.
class ActiveSupport::TestCase
parallelize(workers: 2, with: :threads)
end
The guide also says applications generated with JRuby include the thread option. Process setup and teardown hooks are not available for the threaded model. Code placed in those hooks cannot therefore be assumed to prepare every supported parallel execution configuration.
Threads share their process, so choosing them changes the assumptions about in-memory state. A class-level variable that separate processes would each inherit privately can remain shared among threads. A suite that works under one model has not automatically established that its global state is suitable for the other.
A test assertion should also avoid depending on another example having run first. Separate workers make such a dependency unreliable because the scheduling relationship is outside the assertion. Each example needs to establish the data it requires or use a fixture whose lifecycle the test framework defines.
The choice should reflect the interpreter and the suite's isolation requirements. Process boundaries can help separate mutable memory, while threads require a more direct account of shared state. Both can still encounter shared external resources. The common word parallel does not make their isolation properties identical.
The candidate tests the integration of these contracts
The first Rails 6 beta announcement introduced parallel testing alongside the new frameworks and multiple-database support. By rc2, the versioned guide is a better source for the exact process-versus-thread behavior than a brief feature summary. It states which model creates databases per process and which hooks belong to that model.
The worker count also needs to match the machine running the suite. Using more workers creates more concurrent demand on its database and other resources. A fixed configuration can make that demand understandable, while the documented PARALLEL_WORKERS environment setting permits a different count for another environment. Faster scheduling alone cannot create additional memory or database capacity.
For a release-candidate evaluation, this makes the important question concrete. The suite needs to preserve its assertions when examples overlap under the chosen model. Rails supplies database separation for process workers, and application tests supply the remaining resource ownership. A failure at either boundary is useful evidence about how the application and candidate framework interact.