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

Question about GoodJob Batches in tests #1479

Open
kevinrobayna opened this issue Sep 4, 2024 · 7 comments
Open

Question about GoodJob Batches in tests #1479

kevinrobayna opened this issue Sep 4, 2024 · 7 comments

Comments

@kevinrobayna
Copy link

kevinrobayna commented Sep 4, 2024

👋🏻

We are currently getting started with GoodJob Batches and we reached a slight nitpick 🤣

We currently have the following code:

ApplicationRecord.transaction(requires_new: true) do
  batch = GoodJob::Batch.new

  batch.add do
    Job.perform_later(critical_arg: "1")
    Job.perform_later(critical_arg: "2")
    Job.perform_later(critical_arg: "3")
    Job.perform_later(critical_arg: "4")
  end

  batch.enqueue(on_success: Frodo::Throw::Ring),
end

but on our tests since jobs run inlined we are forced to stub the batch class so that it does not blow up. Is there a more elegant way to do this?

describe "Topic" do
  before do
    # Because we are executing jobs inline job#batch is not populated and we need to
    # hack that with code below.
    dummy_gj_batch = double
    allow(dummy_gj_batch).to receive(:add).and_yield
    allow_any_instance_of(ClassThatEnqueuesBatch).to receive(:batch).and_return(dummy_gj_batch)
  end
end

Happy to raise a PR on the README with the findings!

@thomasschafer
Copy link

thomasschafer commented Sep 4, 2024

Jumping in to say that I'm seeing the same issue - with the inline adapter, running new jobs with perform_later works just as expected, and I see the jobs run as part of the test. When I try and run jobs in a batch, however, they just don't seem to run

@bensheldon
Copy link
Owner

That's not good! Can you share the exception(s) that you're getting?

GoodJob batches are intended to run in any GoodJob execution mode.

@kevinrobayna
Copy link
Author

That's not good! Can you share the exception(s) that you're getting?

GoodJob batches are intended to run in any GoodJob execution mode.

sorry for the late reply but is just a good old

      NoMethodError:
        undefined method `add' for nil

@kevinrobayna
Copy link
Author

I'm going to try to reproduce it on a dummy app though (public 😅)

@kevinrobayna
Copy link
Author

kevinrobayna commented Sep 10, 2024

I figured out what is wrong...

In our current setup the issue is that we are doing Complex Batching so we have more a tree of things

so if we come back to our example

ApplicationRecord.transaction(requires_new: true) do
  batch = GoodJob::Batch.new

  batch.add do
    Job.perform_later(critical_arg: "1")
    Job.perform_later(critical_arg: "2")
    Job.perform_later(critical_arg: "3")
    Job.perform_later(critical_arg: "4")
  end

  batch.enqueue(on_success: Frodo::Throw::Ring),
end

From Job we try to access the batch and add more jobs from that step. So i think there's nothing wrong with GoodJob is just a matter of us setting up the test wrong most likely because there's no batch available to the job on the test.

So I guess we should do something like

RSpec.describe CoolJob do
  subject(:run) do
    GoodJob::Batch.enqueue do
      described_class.perform_now(important_arg: "1")
    end
  end
end

@kevinrobayna
Copy link
Author

kevinrobayna commented Sep 10, 2024

The case above is also happening on our "end_to_end" specs which basically means we run with truncate mode on and we do this little magic on the "spec_helper"

config.include(Module.new do
  # Without this, the perform_enqueued_jobs block below has no effect, because it sets
  # perform_enqueued_jobs on ActiveJob::Base.queue_adapter, yet
  # ActiveJob::TestHelper#queue_adapter_for_test by default instantiates a _new_
  # ActiveJob::QueueAdapters::TestAdapter.new (this happens in a before(:example)), whose
  # perform_enqueued_jobs attribute would of course still have the default value of nil.
  def queue_adapter_for_test
    if ActiveJob::Base.queue_adapter.is_a?(ActiveJob::QueueAdapters::TestAdapter)
      ActiveJob::Base.queue_adapter
    else
      super
    end
  end
end)


config.around do |example|
  DatabaseCleaner.strategy = :truncation if example.metadata[:integration]
  DatabaseCleaner.cleaning do
    if example.metadata[:integration] || example.metadata[:perform_workers]
      perform_enqueued_jobs do
        example.run
      end
    else
      example.run
    end
  end
end

@kevinrobayna
Copy link
Author

So yeah i think the first case is something maybe of a wrong setup the 2nd bit might be something a bit harder to figure out 😅

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

No branches or pull requests

3 participants