Class: GraphQL::Schema::TimeoutMiddleware

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/schema/timeout_middleware.rb

Overview

This middleware will stop resolving new fields after max_seconds have elapsed. After the time has passed, any remaining fields will be nil, with errors added to the errors key. Any already-resolved fields will be in the data key, so you'll get a partial response.

You can provide a block which will be called with any timeout errors that occur.

Note that this will stop a query in between field resolutions, but it doesn't interrupt long-running resolve functions. Be sure to use timeout options for external connections. For more info, see www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/

Examples:

Stop resolving fields after 2 seconds

MySchema.middleware << GraphQL::Schema::TimeoutMiddleware.new(max_seconds: 2)

Notifying Bugsnag on a timeout

MySchema.middleware << GraphQL::Schema::TimeoutMiddleware(max_seconds: 1.5) do |timeout_error, query|
 Bugsnag.notify(timeout_error, {query_string: query_ctx.query.query_string})
end

Defined Under Namespace

Classes: TimeoutError, TimeoutQueryProxy

Constant Summary collapse

DEFAULT_CONTEXT_KEY =

This key is used for storing timeout data in the Query::Context instance

:__timeout_at__

Instance Method Summary collapse

Constructor Details

#initialize(max_seconds:, context_key: DEFAULT_CONTEXT_KEY, &block) ⇒ TimeoutMiddleware

Returns a new instance of TimeoutMiddleware

Parameters:

  • max_seconds (Numeric)

    how many seconds the query should be allowed to resolve new fields

  • context_key (Symbol)

    what key should be used to read and write to the query context


30
31
32
33
34
# File 'lib/graphql/schema/timeout_middleware.rb', line 30

def initialize(max_seconds:, context_key: DEFAULT_CONTEXT_KEY, &block)
  @max_seconds = max_seconds
  @context_key = context_key
  @error_handler = block
end

Instance Method Details

#call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware) ⇒ Object


36
37
38
39
40
41
42
43
44
# File 'lib/graphql/schema/timeout_middleware.rb', line 36

def call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware)
  timeout_at = query_context[@context_key] ||= Time.now + @max_seconds

  if timeout_at < Time.now
    on_timeout(parent_type, parent_object, field_definition, field_args, query_context)
  else
    next_middleware.call
  end
end

#on_timeout(parent_type, parent_object, field_definition, field_args, field_context) ⇒ GraphQL::Schema::TimeoutMiddleware::TimeoutError

This is called when a field would be resolved, except that we're over the time limit.

Returns:


48
49
50
51
52
53
54
55
# File 'lib/graphql/schema/timeout_middleware.rb', line 48

def on_timeout(parent_type, parent_object, field_definition, field_args, field_context)
  err = GraphQL::Schema::TimeoutMiddleware::TimeoutError.new(parent_type, field_definition)
  if @error_handler
    query_proxy = TimeoutQueryProxy.new(field_context.query, field_context)
    @error_handler.call(err, query_proxy)
  end
  err
end