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

Would you be ok with making Prosopite.pause, Prosopite.scan, and Prosopite.resume handle nesting? #43

Open
oskarpearson opened this issue May 16, 2022 · 1 comment

Comments

@oskarpearson
Copy link
Contributor

Hi @charkost

I've a situation where my specs do something like this:

let(:x) { create(:something) }
it "does that thing" do
  SomeService.new(something).call
end

The create(:something) uses FactoryBot to build a whole series of nested objects and relationships. I've wrapped specs in Prosopite.scan blocks as per https://github.com/charkost/prosopite

In my factories, some parts of the build code perform N+1 queries, and the let clause is triggering them. Since I'm trying to find N+1s in SomeService (not in my FactoryBot Factories) I'd like to ignore them. First question: Do you know of some way to avoid that?

The second problem that I'm encountering is that it doesn't seem that the pause/resume functionality is built with nesting in mind. If I pause at the top level, and then pause/resume in a 'lower' level, the second resume will un-pause the first pause. So if I Prosopite.pause inside a factorybot builder, and that builder uses another factorybot builder that also uses Prosopite.pause/Prosopite.resume, the second Prosopite.resume un-pauses the first one.

Here's a test that shows the behaviour.

  def test_pause_reentrant
    # 20 chairs, 4 legs each
    chairs = create_list(:chair, 20)
    chairs.each { |c| create_list(:leg, 4, chair: c) }

    Prosopite.scan
    # Immediately pause
    Prosopite.pause

    Chair.last(20).each do |c|
      Prosopite.pause
      c.legs.last
      Prosopite.resume
    end

    # This shouldn't trigger N+1s because we paused before the each loop above
    Chair.last(20).each do |c|
      c.legs.last
    end
    Prosopite.resume

    assert_no_n_plus_ones
  end

One way to avoid this would be to change pause and resume to increment a counter, and only resume fully on when the most-outmost resume is set. That'd mean undoing 98bcb2b though. I think there are other ways to deal with that problem though (someone calling resume when scan hadn't been called.

@oskarpearson oskarpearson changed the title Would you be ok with making Prosopite.pause and Prosopite.resume handle nesting? Would you be ok with making Prosopite.pause, Prosopite.scan, and Prosopite.resume handle nesting? May 16, 2022
@oskarpearson
Copy link
Contributor Author

oskarpearson commented May 16, 2022

Related: flyerhzm/bullet#435 and flyerhzm/bullet#120

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

No branches or pull requests

1 participant