Skip to content

Instantly share code, notes, and snippets.

@rmosolgo
Created December 25, 2020 18:50
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 rmosolgo/55ec9c6739db3e348fb6aeb99377b128 to your computer and use it in GitHub Desktop.
Save rmosolgo/55ec9c6739db3e348fb6aeb99377b128 to your computer and use it in GitHub Desktop.
fiber_batch_loader.rb
require "fiber"
# Set up a pretend database
DATA = {
1 => "Hannah Coulter",
2 => "Jayber Crow",
3 => "That Distant Land"
}
# This loader will fetch items in batches of IDs
class Loader
def initialize
@ids = []
@data = {}
end
def load(id)
p "Adding #{id}"
@ids << id
Fiber.yield
# Assumes that any batchable IDs will be added to this loader in the interim
sync
@data[id]
end
def sync
if @ids.any?
p "syncing #{@ids}"
@ids.each { |id| @data[id] = DATA[id] }
@ids = []
end
end
end
LOADER = Loader.new
def load_book(id:)
# The important thing here is that the batch loading is completely hidden
title = LOADER.load(id)
title.upcase
end
# This is the pretend GraphQL-Ruby runtime:
results = [nil, nil, nil]
# {path, fiber} tuples
fields = [
[0, Fiber.new { load_book(id: 1) }],
[1, Fiber.new { load_book(id: 2) }],
[2, Fiber.new { load_book(id: 3) }],
]
while ((idx, f) = fields.shift) && (f.alive?)
res = f.resume
if f.alive?
fields << [idx, f]
else
results[idx] = res
end
end
pp results
# % ruby fiber_test.rb
# "Adding 1"
# "Adding 2"
# "Adding 3"
# "syncing [1, 2, 3]"
# ["HANNAH COULTER", "JAYBER CROW", "THAT DISTANT LAND"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment