Class: GraphQL::Schema::Timeout
- Inherits:
-
Object
- Object
- GraphQL::Schema::Timeout
- Defined in:
- lib/graphql/schema/timeout.rb
Overview
This plugin 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 subclass GraphQL::Schema::Timeout
and override max_seconds
and/or handle_timeout
to provide custom logic when a timeout error occurs.
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/
Defined Under Namespace
Classes: TimeoutError
Class Method Summary collapse
Instance Method Summary collapse
-
#handle_timeout(error, query) ⇒ Object
Invoked when a query times out.
-
#initialize(max_seconds:) ⇒ Timeout
constructor
A new instance of Timeout.
-
#max_seconds(query) ⇒ Integer, false
Called at the start of each query.
- #trace(key, data) ⇒ Object
Constructor Details
#initialize(max_seconds:) ⇒ Timeout
Returns a new instance of Timeout.
42 43 44 |
# File 'lib/graphql/schema/timeout.rb', line 42 def initialize(max_seconds:) @max_seconds = max_seconds end |
Class Method Details
.use(schema, **options) ⇒ Object
36 37 38 39 |
# File 'lib/graphql/schema/timeout.rb', line 36 def self.use(schema, **) tracer = new(**) schema.tracer(tracer) end |
Instance Method Details
#handle_timeout(error, query) ⇒ Object
Invoked when a query times out.
105 106 107 |
# File 'lib/graphql/schema/timeout.rb', line 105 def handle_timeout(error, query) # override to do something interesting end |
#max_seconds(query) ⇒ Integer, false
Called at the start of each query.
The default implementation returns the max_seconds:
value from installing this plugin.
98 99 100 |
# File 'lib/graphql/schema/timeout.rb', line 98 def max_seconds(query) @max_seconds end |
#trace(key, data) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/graphql/schema/timeout.rb', line 46 def trace(key, data) case key when 'execute_multiplex' data.fetch(:multiplex).queries.each do |query| timeout_duration_s = max_seconds(query) timeout_state = if timeout_duration_s == false # if the method returns `false`, don't apply a timeout false else now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) timeout_at = now + (max_seconds(query) * 1000) { timeout_at: timeout_at, timed_out: false } end query.context.namespace(self.class)[:state] = timeout_state end yield when 'execute_field', 'execute_field_lazy' query_context = data[:context] || data[:query].context timeout_state = query_context.namespace(self.class).fetch(:state) # If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query. if timeout_state != false && Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at) error = if data[:context] GraphQL::Schema::Timeout::TimeoutError.new(query_context.parent_type, query_context.field) else field = data.fetch(:field) GraphQL::Schema::Timeout::TimeoutError.new(field.owner, field) end # Only invoke the timeout callback for the first timeout if !timeout_state[:timed_out] timeout_state[:timed_out] = true handle_timeout(error, query_context.query) end error else yield end else yield end end |