-
Notifications
You must be signed in to change notification settings - Fork 73
Server: Interceptors
gruf supports interceptors around the grpc server calls, allowing you to perform actions around your service method calls. This can be used to add tracing data, connection resets in the grpc thread pool, further instrumentation, and other things.
Adding a hook is as simple as creating a class that extends Gruf::Interceptor::ServerInterceptor
,
and a call
method that yields control to get the method result:
class MyInterceptor < ::Gruf::Interceptors::ServerInterceptor
def call
yield
end
end
Interceptors have access to the request
object, which is the Gruf::Controller::Request
object
described above.
Interceptors can fail requests with the same method calls as a controller:
class MyFailingInterceptor < ::Gruf::Interceptors::ServerInterceptor
def call
result = yield # this returns the protobuf message
unless result.dont_hijack
# we'll assume this "dont_hijack" attribute exists on the message for this example
fail!(:internal, :hijacked, 'Hijack all the things!')
end
result
end
end
Similarly, you can raise GRPC::BadStatus
calls to trigger similar errors without accompanying metadata.
From there, the interceptor can be added to the server manually (if not executing via bundle exec gruf
):
server = Gruf::Server.new
server.add_interceptor(MyInterceptor, option_foo: 'value 123')
Or, alternatively, the more common method of passing them into the interceptors
configuration hash:
Gruf.configure do |c|
c.interceptors.use(MyInterceptor, option_foo: 'value 123')
end
Interceptors each wrap the call and are run recursively within each other. This means that if you have
three interceptors - Interceptor1
, Interceptor2
, and Interceptor3
- they will run in FIFO
(first in, first out) order. Interceptor1
will run, yielding to Interceptor2
,
which will then yield to Interceptor3
, which will then yield to your service method call,
ending the chain.
You can utilize the insert_before
and insert_after
methods to maintain order:
Gruf.configure do |c|
c.interceptors.use(Interceptor1)
c.interceptors.use(Interceptor2)
c.interceptors.insert_before(Interceptor2, Interceptor3) # 3 will now happen before 2
c.interceptors.insert_after(Interceptor1, Interceptor4) # 4 will now happen after 1
end
By default, the ActiveRecord Connection Reset interceptor and Output Metadata Timing interceptor
are loaded into gruf unless explicitly told not to via the use_default_interceptors
configuration
parameter.
You can pass contextual data between interceptors - or down into the Gruf Controller - via the request's context hash. This can be done like so:
class MyInterceptor < ::Gruf::Interceptors::ServerInterceptor
def call
request.context[:foo] = 'bar'
yield
end
end
This will then be available to the Gruf controller as a hash via request.context
.
Next: Server: Hooks