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

Assert cancelled jobs #724

Closed
jofrly opened this issue Oct 18, 2022 · 4 comments
Closed

Assert cancelled jobs #724

jofrly opened this issue Oct 18, 2022 · 4 comments

Comments

@jofrly
Copy link

jofrly commented Oct 18, 2022

Hi!

My application schedules jobs and utilizes the .set(wait: ... alot.

Sometimes, I cancel jobs when certain events occur in the application.
I do that by destroying the record in the good_jobs table.

GoodJob::Execution.where(id: provider_job_id).take.destroy

My application grows in complexity so I want to introduce some tests.
I'd like to test one part of the application where a job gets cancelled like explained above.

However the assert_enqueued_jobs helper does not "respect" the cancelled jobs.
Is there another way to assert enqueued jobs?

I tried to query them like this

GoodJob::Execution.job_class(MyJob).size

However that always returns 0 in the test environment somehow.
Scheduling, cancelling and querying them in the way I mentioned works fine in other environments though...

Thankful for any help / advice.

@bensheldon
Copy link
Owner

@jofrly thanks for opening the issue. I'm happy to help.

First, if you're using assert_enqueued_jobs, then that means that you're using Rail's TestAdapter (e.g. queue_adapter = :test) and not GoodJob. The ActiveJob test helpers, like assert_enqueued_jobs are tied in together with the TestAdapter; basically the test adapter "enqueues" jobs to an array, and then the test helpers assert on the contents of the array. It bypasses GoodJob entirely, which is why you're unable to find those job records in GoodJob's database tables.

If you wanted to use GoodJob in your tests, you would use something like this:

# "external" execution mode will store the records but not execute them
ActiveJob::Base.queue_adapter = GoodJob::Adapter.new(execution_mode: :external)

# "inline" will execute them immediately
ActiveJob::Base.queue_adapter = GoodJob::Adapter.new(execution_mode: :inline)

Second, I want to suggest a safer way to cancel jobs: GoodJob::Job#discard_job. Calling destroy directly on the record could result in unexpected behavior with GoodJob. Discarding would be better than destroying, because discarding the job first will try to take an Advisory Lock on the job and not delete the record if it is already locked (e.g. executing).

job = GoodJob::Job.find_by(active_job_id: job_id)
job.discard_job("Canceled the job because it's no longer needed")

@jofrly
Copy link
Author

jofrly commented Oct 18, 2022

@bensheldon thanks so much for answering so quickly!

The active_job.queue_adapter is set to :good_job and the execution mode is set to :inline. I tried to set it to :external but that didn't change anything regarding the tests.

I noticed I was on good_job (2.9.1) so I created a new repo with good_job (3.5.0) just to test if that changes something: jofrly/goodjobtest@1b19f1d

I created a job SendNotificationJob and a test SendNotificationJobTest which schedules the job and then prints out GoodJob::Execution.count and GoodJob::ActiveJobJob.count.

My assumption is to see a 1 in the output but when running rails test I get zeroes:

Running 1 tests in a single process (parallelization threshold is 50)
Run options: --seed 25153

# Running:

0
0
.

Finished in 0.021458s, 46.6027 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 0 errors, 0 skips

So I'm not quite sure what I'm doing wrong. Could you take a look at my repo?

@bensheldon
Copy link
Owner

@jofrly aha! I think you are experiencing Rail's very aggressive ActiveJob test adapter: rails/rails#37270

In your test, if you output SendNotificationJob.queue_adapter I think you'll find it's still the Test adapter.

You need to do something like this in your Job setup (I'm not sure what the minitest equivalent is):

RSpec.configure do |config|
config.prepend_before do
# https://github.com/rails/rails/issues/37270
descendants = ActiveJob::Base.descendants + [ActiveJob::Base]
descendants.each(&:disable_test_adapter)
end

@jofrly
Copy link
Author

jofrly commented Oct 19, 2022

@bensheldon yes!

logging SendNotificationJob.queue_adapter showed that it used the ActiveJob::QueueAdapters::TestAdapter.
I added the code you mentioned to the setup of my test:

class MyTest < ActionDispatch::IntegrationTest
  setup do
    descendants = ActiveJob::Base.descendants + [ActiveJob::Base]
    descendants.each(&:disable_test_adapter)
  end

  ...

and now everything works as expected. Thanks so much for helping me. Coffee is on me :)

@jofrly jofrly closed this as completed Oct 19, 2022
Repository owner moved this from Inbox to Done in GoodJob Backlog v2 Oct 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

2 participants