Skip to content

Instantly share code, notes, and snippets.

@shaunakpp
Created July 18, 2017 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shaunakpp/eb23cb20a2153898084f39ad14b53920 to your computer and use it in GitHub Desktop.
Save shaunakpp/eb23cb20a2153898084f39ad14b53920 to your computer and use it in GitHub Desktop.
lazy staggered iteration
class Lookup
attr_reader :person, :service
def initialize(person)
@person = person
@service = ThirdPartyService.new
end
def find_match
lookups = [
expensive_phone_lookup(@person.email),
expensive_location_lookup(@person.email),
expensive_property_lookup(@person.email),
]
lookups.each do |lookup|
result = @service.match_person(stage)
break result if result.success?
end
end
def find_match
while stage = stages(@person.email).next
result = @service.match_person(stage)
break result if result.success?
end
rescue StopIteration => _
# error handling here
end
def stages(email)
@stages ||= Enumerator.new do |enumerator|
# Step 1: Only Phone
phone = expensive_phone_lookup(email)
enumerator.yield(:email_only, :phone => phone)
# Step 2: Only Phone Number
location = expensive_location_lookup(email)
enumerator.yield(:location_only, :location => location)
# Step 3: Only Property
property = expensive_property_lookup(email)
enumerator.yield(:property, :property => property)
# Step 4: All Info
enumerator.yield(:all_info, all_info)
end
end
end
We are fetching person data from an third party service like Clearbit or FullContact using his/her email.
Each type of data like phones, location, properties, are expensive computationally and monetarily.
If we use a traditional collection like Array for this, the array will be eager loaded and all the expensive lookups will happen at the same time
But we dont want that do we ?
So lets use an enumerator.
# Stop on Success
def find_match(previous_step = nil)
current_step, lookup_data = steps.next
result = @service.match_person(lookup_data)
if result.failure?
return find_match(current_step)
end
Result.new(current_step, :found, result)
rescue StopIteration => _
return Result.new(previous_step, :not_found, document = nil)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment