Skip to content

Warming the cache #59

Description

@sj26

We load some records to place into the graphql context before running a query. I'd like to warm the graphql batch loader caches with these records. At the moment I'm doing something like this (with a contrived example):

# app/graphql/record_loader.rb
class RecordLoader < GraphQL::Batch::Loader
  def initialize(record_class)
    @record_class = record_class
    @primary_key = record_class.primary_key
  end

  def perform(keys)
    # Resolve unfulfilled keys
    records_by_key = @record_class.where(@primary_key => keys).index_by(&@primary_key)

    # Fulfills both found keys as records, and unfound keys as nil
    keys.each { |key| fulfill(key, records_by_key[key]) }
  end

  def warm(record)
    key = record.public_send(@primary_key)
    promise = cache[cache_key(key)] ||= Promise.new.tap { |promise| promise.source = self }
    promise.fulfill(record) unless promise.fulfilled?
  end
end
# app/graphql/schema.rb
Schema = GraphQL::Schema.define do
  # ...
  use GraphQL::Batch
  use GraphQL::Batch::Warmer, with: -> (query) do
    RecordLoader.for(User).warm(query.context[:current_user])
  end
  # ...
end
# lib/graphql/batch/warmer.rb
module GraphQL::Batch::Warmer
  def self.use(schema_defn, with:)
    schema_defn.instrument(:query, QueryInstrumenter.new(with))
  end

  class QueryInstrumenter
    def initialize(block)
      @block = block
    end

    def before_query(query)
      unless GraphQL::Batch::Executor.current
        raise "Move `use GraphQL::BatchWarmer` below `use GraphQL::Batch` in your schema, or remove it"
      end

      @block.call(query)
    end

    def after_query(query)
    end
  end
end

This feels like it dips a little too much into this gem's responsibilities. Is there any interest including some sort of cache warming facility in this gem?

Update: I've simplified the example.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions