Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active Job: Correctly use the desired test adapter in tests #48585

Merged
merged 1 commit into from May 9, 2024

Conversation

ghiculescu
Copy link
Member

@ghiculescu ghiculescu commented Jun 27, 2023

Motivation / Background

Currently if you set config.active_job.queue_adapter = (anything) in config/application.rb or config/environments/test.rb, this config will be respected by some test cases but not others.

Specifically, in ActionDispatch::IntegrationTest, ActionMailer::TestCase, and ActiveJob::TestCase, the test adapter will still be TestAdapter, while in other test cases it will be InlineAdapter.

I think you'd expect that if you set the test adapter for an environment, that test adapter would be available everywhere in that environment. For example, you might want to use the Delayed Job test adapter in your test environment so that you can have your test code more closely match production. The feedback on #37270 echoes this, but the workaround suggested there of disabling the test adapter on specific klasses is not reliable.

Detail

The logic to determine which queue adapter a job uses is quite confusing.

Here is how it works on main currently:

  1. If running in a test, and the test class includes ActiveJob::TestHelper and overrides queue_adapter_for_test, then the queue_adapter_for_test adapter is used.
  2. Otherwise, if running in a test, and the test class includes ActiveJob::TestHelper, then the :test adapter is used.
  3. Otherwise, if self.queue_adapter is set on the job class, that adapter is used.
  4. Otherwise, if self.queue_adapter is set on the job's superclass (eg. ApplicationJob), that adapter is used.
  5. Fall back to Rails.application.config.active_job.queue_adapter as configured by the user.
  6. If not configured by the user, Rails.application.config.active_job.queue_adapter defaults to :async.
  7. Fall back to :async if no Rails config set (eg. using Active Job as a standalone).

As noted above, only some of the built in test classes include ActiveJob::TestHelper. Also, setting a queue adapter on a specific job class is rare (typically you would not want different jobs to be performed by different backends). So in practice, in development/production, option 5 is used. And in test, options 2 and 5 are used, depending on the type of test.

This PR changes the logic to work as follows:

  1. If self.queue_adapter is set on the job class, that adapter is used.
  2. Otherwise, if self.queue_adapter is set on the job's superclass (eg. ApplicationJob), that adapter is used.
  3. If running in a test, and the test class includes ActiveJob::TestHelper and overrides queue_adapter_for_test, then the queue_adapter_for_test adapter is used.
  4. Fall back to Rails.application.config.active_job.queue_adapter as configured by the user.
  5. If not configured by the user, Rails.application.config.active_job.queue_adapter defaults to :test if Rails.env.test?, otherwise it defaults to :async.
  6. If running in a test, and the test class includes ActiveJob::TestHelper, and no other adapter has been set (eg. using Active Job as a standalone), then use :test.
  7. Otherwise, fall back to :async.

The key changes are:

  • Now, if you set a queue_adapter on a job class, that will always be respected.
  • The queue_adapter_for_test override still works, but it no longer takes priority over a queue adapter set on a specific job class. Since I think both of these techniques are rare, and the impact of this change only exists in a test environment, I think it is a relatively safe change.
  • The default queue adapter in Rails config is now env-dependent. (It's :test in the test environment, and :async in all others.)

The default rails environment templates suggest setting a specific queue adapter only in production. For users who do that, there will be no changes to behaviour with this PR.

For users who are more granular, by setting per-job queue adapters, things should continue to work as expected with this PR.

The real change is for users who set a default queue adapter across all environments (as in this issue: #37270). For them, this PR solves the issue where some tests use the desired queue adapter, and other tests don't.

Additional information

Fixes: #37270

ref: bensheldon/good_job#846
ref: #26360 - this PR changes the behavior here, which I think was overzealous.

I extracted out some other PRs to fix internal issues while working on this: #48623, #48626. I also extracted #48599 out as a non-controversial fix prior to this PR.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one change. Changes that are unrelated should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message. Ex: [Fix #issue-number]
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature. Minor bug fixes and documentation changes should not be included.

Copy link

@cmunny95 cmunny95 left a comment

Choose a reason for hiding this comment

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

Seems like a solid approach to me and it would be great to see this fixed! I'd be happy to run the patch and verify once the test suite has been updated

@ghiculescu ghiculescu changed the title Active Job: Correctly use the desired test adapter in tests (RFC) Active Job: Correctly use the desired test adapter in tests Jul 2, 2023
@ghiculescu ghiculescu force-pushed the active-job-test-adapter branch 2 times, most recently from f94467c to 1c50e04 Compare July 2, 2023 10:40
@rails-bot rails-bot bot added the docs label Jul 2, 2023
@ghiculescu ghiculescu force-pushed the active-job-test-adapter branch 2 times, most recently from f35f0f7 to 1ee7198 Compare July 2, 2023 10:47
@ghiculescu ghiculescu marked this pull request as ready for review July 2, 2023 10:49
ghiculescu added a commit to ghiculescu/rails that referenced this pull request Jul 2, 2023
…mediate` set

This is an internal fix, not user facing. I noticed it while working on rails#48585.

The `async` adapter has an `immediate` option, which should only be used in tests. This option should tell the adapter to run jobs inline. This works correctly with `perform_later`, but it does not work with `enqueue_at`, which is what other internal mechanisms such as `retry_job` use.

This PR fixes this bug.
@ghiculescu ghiculescu force-pushed the active-job-test-adapter branch 4 times, most recently from 440fb35 to c060ecf Compare July 3, 2023 00:44
@zzak zzak added this to the 7.1.0 milestone Sep 20, 2023
@ghiculescu ghiculescu force-pushed the active-job-test-adapter branch 3 times, most recently from 2c72e41 to 4b297aa Compare September 25, 2023 00:30
@rafaelfranca rafaelfranca removed this from the 7.1.0 milestone Sep 25, 2023
@northeastprince
Copy link
Contributor

@rafaelfranca can we get this merged?

@jrochkind
Copy link
Contributor

This would be a really welcome fix to a very confusing challenge in setting up your tests how you want. (I actually do want some test classes using :inline and others using :test).

It would be great if some way could be found to get maintainer attention to make progress on this!

@zzak zzak added this to the 7.2.0 milestone Jan 14, 2024
@gjtorikian
Copy link
Contributor

I understand this is slated for 7.2. But for those of us who prefer to pin the rails dependency to a SHA, could this be merged ?

@ghiculescu
Copy link
Member Author

I don't know if it'll be in 7.2. @byroot or @rafaelfranca do you have a verdict on that? If this is something you're conceptually okay with, I will work on the merge conflicts to get it mergable 👍

@byroot
Copy link
Member

byroot commented May 6, 2024

I don't have full context and wonder why it was done that way, but your point make sense to me.

I'd say rebase and ping me when it's done. Rafael can revert if he disagrees.

Copy link
Member Author

Choose a reason for hiding this comment

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

@jonathanhefner in light of your recent docs changes, I'd love if you could review if the docs in this file all make sense for this PR 😍

@ghiculescu ghiculescu requested review from byroot and removed request for byroot May 7, 2024 06:15


class EnqueuedJobsTest < ActiveJob::TestCase
if adapter_is?(:test)
Copy link
Member Author

Choose a reason for hiding this comment

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

This is needed becuase you can't skip since #50188. Alternative would be to put a force_skip in a setup block.

@ghiculescu ghiculescu force-pushed the active-job-test-adapter branch 4 times, most recently from d55bd17 to 9526d52 Compare May 8, 2024 01:43
@ghiculescu ghiculescu requested a review from byroot May 8, 2024 01:44
activejob/CHANGELOG.md Outdated Show resolved Hide resolved
@byroot byroot merged commit 80fa112 into rails:main May 9, 2024
4 checks passed
@@ -0,0 +1,217 @@
# frozen_string_literal: true
Copy link
Member

Choose a reason for hiding this comment

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

I would have liked to see this in railties/test/application/active_job/adapter_test.rb, like #51036. That directory is kinda messy, and it'd be nice if they were organized by framework where applicable

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh I didn't know that existed. Happy to move the test, or you can if you like.

Copy link
Member

Choose a reason for hiding this comment

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

It's just a knit, but I think moving files around is cosmetic enough to not warrant a PR. Maybe next time? 🙏

@searls
Copy link
Contributor

searls commented May 10, 2024

Thanks so much for digging into this and fixing it!! Bumps to #37270 have been irritating my inbox for nearly 5 years! ❤️

@kmcphillips
Copy link
Contributor

This is really great and detailed research work, fixing a hard to follow problem. Thank you! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rails 6 inconsistently overrides ActiveJob queue_adapter setting with TestAdapter
10 participants