Read more

Be careful when checking scopes for blankness

Dominic Beger
February 14, 2024Software engineer at makandra GmbH

Today I stumbled across a pretty harmless-looking query in our application which turned out to be pretty harmful and caused huge memory usage as well as downing our passenger workers by letting requests take up to 60 seconds. We had a method that received a scope and then checked, if the scope parameter was blank? and aborted the method execution in this case.

def foo(scope)
  return if scope.blank?
  
  # Use scope, e.g.
  scope.find(...)
end
Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

We then called this method with an all scope: foo(Media::Document::Base.all). Be careful with this. all returns a scope (ActiveRecord::Relation) which looks and is harmless at first because nothing is loaded into memory at that point. However, calling .all.blank? loads all records into memory and then evaluates, if the scope is blank.

What you are searching for is a normal nil check or maybe ActiveRecord::FinderMethods.exists? Show archive.org snapshot .

def foo(scope)
  return unless scope
  
  # Use scope, e.g.
  scope.find(...)
end
def foo(scope)
  return unless scope&.exists?
  
  # Use scope, e.g.
  scope.find(...)
end

This will produce an additional query in the database, but is fast and does not load any records into memory.

Posted by Dominic Beger to makandra dev (2024-02-14 14:41)