gruf 1.2.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +98 -119
- data/bin/gruf +9 -3
- data/lib/gruf.rb +4 -4
- data/lib/gruf/configuration.rb +11 -20
- data/lib/gruf/controllers/base.rb +82 -0
- data/lib/gruf/controllers/request.rb +96 -0
- data/lib/gruf/controllers/service_binder.rb +86 -0
- data/lib/gruf/error.rb +9 -0
- data/lib/gruf/errors/helpers.rb +40 -0
- data/lib/gruf/{hooks → interceptors}/active_record/connection_reset.rb +4 -10
- data/lib/gruf/interceptors/authentication/basic.rb +80 -0
- data/lib/gruf/interceptors/base.rb +51 -0
- data/lib/gruf/{instrumentation/output_metadata_timer.rb → interceptors/context.rb} +25 -15
- data/lib/gruf/interceptors/instrumentation/output_metadata_timer.rb +59 -0
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/base.rb +15 -13
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/logstash.rb +15 -13
- data/lib/gruf/{instrumentation → interceptors/instrumentation}/request_logging/formatters/plain.rb +21 -19
- data/lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb +191 -0
- data/lib/gruf/interceptors/instrumentation/statsd.rb +80 -0
- data/lib/gruf/interceptors/registry.rb +131 -0
- data/lib/gruf/{authentication/none.rb → interceptors/server_interceptor.rb} +8 -7
- data/lib/gruf/interceptors/timer.rb +79 -0
- data/lib/gruf/response.rb +1 -2
- data/lib/gruf/server.rb +40 -25
- data/lib/gruf/version.rb +1 -1
- metadata +19 -20
- data/lib/gruf/authentication.rb +0 -65
- data/lib/gruf/authentication/base.rb +0 -65
- data/lib/gruf/authentication/basic.rb +0 -74
- data/lib/gruf/authentication/strategies.rb +0 -107
- data/lib/gruf/hooks/base.rb +0 -66
- data/lib/gruf/hooks/registry.rb +0 -110
- data/lib/gruf/instrumentation/base.rb +0 -114
- data/lib/gruf/instrumentation/registry.rb +0 -104
- data/lib/gruf/instrumentation/request_context.rb +0 -82
- data/lib/gruf/instrumentation/request_logging/hook.rb +0 -185
- data/lib/gruf/instrumentation/statsd.rb +0 -80
- data/lib/gruf/service.rb +0 -333
data/lib/gruf/service.rb
DELETED
@@ -1,333 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
5
|
-
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
6
|
-
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
7
|
-
# persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
-
#
|
9
|
-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
10
|
-
# Software.
|
11
|
-
#
|
12
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
13
|
-
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
14
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
15
|
-
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
-
#
|
17
|
-
module Gruf
|
18
|
-
##
|
19
|
-
# Module for gRPC endpoints. Include this in any gRPC service you wish Gruf to serve. It will automatically mount
|
20
|
-
# it to the given gruf server and can be run via the command:
|
21
|
-
#
|
22
|
-
# bundle exec gruf
|
23
|
-
#
|
24
|
-
module Service
|
25
|
-
extend ActiveSupport::Concern
|
26
|
-
|
27
|
-
included do
|
28
|
-
include Gruf::Loggable
|
29
|
-
|
30
|
-
##
|
31
|
-
# Hook into method_added to add pre/post interceptors for endpoints
|
32
|
-
#
|
33
|
-
# @param [String] method_name
|
34
|
-
#
|
35
|
-
def self.method_added(method_name)
|
36
|
-
return if @__last_methods_added && @__last_methods_added.include?(method_name)
|
37
|
-
return unless rpc_handler_names.include?(method_name)
|
38
|
-
|
39
|
-
rpc_desc = rpc_descs[method_name.to_s.camelcase.to_sym]
|
40
|
-
|
41
|
-
with = :"#{method_name}_with_intercept"
|
42
|
-
without = :"#{method_name}_without_intercept"
|
43
|
-
@__last_methods_added = [method_name, with, without]
|
44
|
-
|
45
|
-
if rpc_desc
|
46
|
-
if rpc_desc.request_response?
|
47
|
-
define_method(with) do |request, call|
|
48
|
-
call_chain(method_name, request, call)
|
49
|
-
end
|
50
|
-
elsif rpc_desc.client_streamer?
|
51
|
-
define_method(with) do |call|
|
52
|
-
call_chain(method_name, nil, call)
|
53
|
-
end
|
54
|
-
elsif rpc_desc.server_streamer?
|
55
|
-
define_method(with) do |request, call, &block|
|
56
|
-
call_chain(method_name, request, call, &block)
|
57
|
-
end
|
58
|
-
else # bidi
|
59
|
-
define_method(with) do |requests, call, &block|
|
60
|
-
call_chain(method_name, requests, call, &block)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
else
|
64
|
-
# fallback to the catch-all
|
65
|
-
define_method with do |*args, &block|
|
66
|
-
call_chain(method_name, *args, &block)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
alias_method without, method_name
|
71
|
-
alias_method method_name, with
|
72
|
-
@__last_methods_added = nil
|
73
|
-
end
|
74
|
-
|
75
|
-
##
|
76
|
-
# Properly find all RPC handler methods
|
77
|
-
#
|
78
|
-
def self.rpc_handler_names
|
79
|
-
rpc_descs.keys.map { |n| n.to_s.underscore.to_sym }.uniq
|
80
|
-
end
|
81
|
-
|
82
|
-
##
|
83
|
-
# Mount the service into the server automatically
|
84
|
-
#
|
85
|
-
def self.mount
|
86
|
-
Gruf.services << name.constantize
|
87
|
-
end
|
88
|
-
|
89
|
-
mount
|
90
|
-
end
|
91
|
-
|
92
|
-
##
|
93
|
-
# Happens before a call.
|
94
|
-
#
|
95
|
-
# @param [Symbol] call_signature The method being called
|
96
|
-
# @param [Object] req The request object
|
97
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
98
|
-
#
|
99
|
-
def before_call(call_signature, req, call)
|
100
|
-
authenticate(call_signature, req, call)
|
101
|
-
Gruf::Hooks::Registry.each do |_name, h|
|
102
|
-
h.new(self, Gruf.hook_options).before(call_signature, req, call) if h.instance_methods.include?(:before)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
##
|
107
|
-
# Happens around a call.
|
108
|
-
#
|
109
|
-
# @param [Symbol] call_signature The gRPC method being called
|
110
|
-
# @param [Object] req The request object
|
111
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
112
|
-
#
|
113
|
-
def around_call(call_signature, req, call, &block)
|
114
|
-
around_hooks = []
|
115
|
-
Gruf::Hooks::Registry.each do |_name, h|
|
116
|
-
around_hooks << h.new(self, Gruf.hook_options) if h.instance_methods.include?(:around)
|
117
|
-
end
|
118
|
-
if around_hooks.any?
|
119
|
-
run_around_hook(around_hooks, call_signature, req, call, &block)
|
120
|
-
else
|
121
|
-
yield
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
##
|
126
|
-
# Run all around hooks recursively, starting with the last loaded
|
127
|
-
#
|
128
|
-
# @param [Array<Gruf::Hooks::Base>] hooks The current stack of hooks
|
129
|
-
# @param [Symbol] call_signature The gRPC method being called
|
130
|
-
# @param [Object] req The request object
|
131
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
132
|
-
#
|
133
|
-
def run_around_hook(hooks, call_signature, req, call, &_)
|
134
|
-
h = hooks.pop
|
135
|
-
h.around(call_signature, req, call) do
|
136
|
-
if hooks.any?
|
137
|
-
run_around_hook(hooks, call_signature, req, call) { yield }
|
138
|
-
else
|
139
|
-
yield
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
##
|
145
|
-
# Happens around the entire call chain - before, around, the call itself, and after hooks.
|
146
|
-
#
|
147
|
-
# @param [Symbol] call_signature The gRPC method being called
|
148
|
-
# @param [Object] req The request object
|
149
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
150
|
-
#
|
151
|
-
def outer_around_call(call_signature, req, call, &block)
|
152
|
-
outer_around_hooks = []
|
153
|
-
|
154
|
-
# run instrumentation hooks as outer_around calls
|
155
|
-
Gruf::Instrumentation::Registry.each do |_name, h|
|
156
|
-
outer_around_hooks << h.new(self, Gruf.instrumentation_options)
|
157
|
-
end
|
158
|
-
|
159
|
-
Gruf::Hooks::Registry.each do |_name, h|
|
160
|
-
outer_around_hooks << h.new(self, Gruf.hook_options) if h.instance_methods.include?(:outer_around)
|
161
|
-
end
|
162
|
-
if outer_around_hooks.any?
|
163
|
-
run_outer_around_hook(outer_around_hooks, call_signature, req, call, &block)
|
164
|
-
else
|
165
|
-
yield
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
##
|
170
|
-
# Run all outer around hooks recursively, starting with the last loaded
|
171
|
-
#
|
172
|
-
# @param [Array<Gruf::Hooks::Base>] hooks The current stack of hooks
|
173
|
-
# @param [Symbol] call_signature The gRPC method being called
|
174
|
-
# @param [Object] req The request object
|
175
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
176
|
-
#
|
177
|
-
def run_outer_around_hook(hooks, call_signature, req, call, &_)
|
178
|
-
h = hooks.pop
|
179
|
-
h.outer_around(call_signature, req, call) do
|
180
|
-
if hooks.any?
|
181
|
-
run_outer_around_hook(hooks, call_signature, req, call) { yield }
|
182
|
-
else
|
183
|
-
yield
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
##
|
189
|
-
# Happens after a call
|
190
|
-
#
|
191
|
-
# @param [Boolean] success Whether or not the result was successful
|
192
|
-
# @param [Object] response The response object returned from the gRPC call
|
193
|
-
# @param [Symbol] call_signature The method being called
|
194
|
-
# @param [Object] req The request object
|
195
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
196
|
-
# @return [Object] If extending this method or using the after_call_hook, you must return the response object
|
197
|
-
#
|
198
|
-
def after_call(success, response, call_signature, req, call)
|
199
|
-
Gruf::Hooks::Registry.each do |_name, h|
|
200
|
-
h.new(self, Gruf.hook_options).after(success, response, call_signature, req, call) if h.instance_methods.include?(:after)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
##
|
205
|
-
# Authenticate the endpoint caller.
|
206
|
-
#
|
207
|
-
# @param [Symbol] _method The method being called
|
208
|
-
# @param [Object] req The request object
|
209
|
-
# @param [GRPC::ActiveCall] call The gRPC active call object
|
210
|
-
#
|
211
|
-
def authenticate(_method, req, call)
|
212
|
-
fail!(req, call, :unauthenticated) unless Authentication.verify(call)
|
213
|
-
end
|
214
|
-
|
215
|
-
##
|
216
|
-
# Will issue a GRPC BadStatus exception, with a code based on the code passed.
|
217
|
-
#
|
218
|
-
# @param [Object] _req The request object being sent
|
219
|
-
# @param [GRPC::ActiveCall] call The gRPC active call
|
220
|
-
# @param [Symbol] error_code The network error code that maps to gRPC status codes
|
221
|
-
# @param [Symbol] app_code The application-specific code for the error
|
222
|
-
# @param [String] message (Optional) A detail message about the error
|
223
|
-
# @param [Hash] metadata (Optional) Any metadata to inject into the trailing metadata for the response
|
224
|
-
#
|
225
|
-
def fail!(_req, call, error_code, app_code = nil, message = '', metadata = {})
|
226
|
-
e = error
|
227
|
-
e.code = error_code.to_sym
|
228
|
-
e.app_code = app_code ? app_code.to_sym : error.code
|
229
|
-
e.message = message.to_s
|
230
|
-
e.metadata = metadata
|
231
|
-
|
232
|
-
cleanup!
|
233
|
-
e.fail!(call)
|
234
|
-
end
|
235
|
-
|
236
|
-
private
|
237
|
-
|
238
|
-
##
|
239
|
-
# Encapsulate the call chain to provide before/around/after hooks
|
240
|
-
#
|
241
|
-
# @param [String] original_call_sig The original call signature for the service
|
242
|
-
# @param [Object] req The request object
|
243
|
-
# @param [GRPC::ActiveCall] call The ActiveCall object being executed
|
244
|
-
# @return [Object] The response object
|
245
|
-
#
|
246
|
-
def call_chain(original_call_sig, req, call, &block)
|
247
|
-
outer_result = outer_around_call(original_call_sig, req, call) do
|
248
|
-
begin
|
249
|
-
before_call(original_call_sig, req, call)
|
250
|
-
|
251
|
-
result = around_call(original_call_sig, req, call) do
|
252
|
-
# send the actual request to gRPC
|
253
|
-
if req.nil?
|
254
|
-
send("#{original_call_sig}_without_intercept", call, &block)
|
255
|
-
else
|
256
|
-
send("#{original_call_sig}_without_intercept", req, call, &block)
|
257
|
-
end
|
258
|
-
end
|
259
|
-
rescue GRPC::BadStatus => e
|
260
|
-
result = e
|
261
|
-
end
|
262
|
-
success = !result.is_a?(GRPC::BadStatus)
|
263
|
-
after_call(success, result, original_call_sig, req, call)
|
264
|
-
|
265
|
-
raise result unless success
|
266
|
-
|
267
|
-
result
|
268
|
-
end
|
269
|
-
cleanup!
|
270
|
-
outer_result
|
271
|
-
rescue GRPC::BadStatus
|
272
|
-
cleanup!
|
273
|
-
raise
|
274
|
-
rescue => e
|
275
|
-
set_debug_info(e.message, e.backtrace) if Gruf.backtrace_on_error
|
276
|
-
error_message = Gruf.use_exception_message ? e.message : Gruf.internal_error_message
|
277
|
-
fail!(req, call, :internal, :unknown, error_message)
|
278
|
-
end
|
279
|
-
|
280
|
-
##
|
281
|
-
# Return the appropriate RPC descriptor for a given call signature on this service
|
282
|
-
#
|
283
|
-
# @return [GRPC::RpcDesc]
|
284
|
-
#
|
285
|
-
def rpc_desc(call_signature)
|
286
|
-
self.class.rpc_descs[call_signature.to_s.camelcase.to_sym]
|
287
|
-
end
|
288
|
-
|
289
|
-
##
|
290
|
-
# Add a field error to this endpoint
|
291
|
-
#
|
292
|
-
# @param [Symbol] field_name The name of the field
|
293
|
-
# @param [Symbol] error_code The application error code for the field
|
294
|
-
# @param [String] message A given error message for the field
|
295
|
-
#
|
296
|
-
def add_field_error(field_name, error_code, message = '')
|
297
|
-
error.add_field_error(field_name, error_code, message)
|
298
|
-
end
|
299
|
-
|
300
|
-
##
|
301
|
-
# Return true if there are any present field errors
|
302
|
-
#
|
303
|
-
# @return [Boolean] True if the service has any field errors
|
304
|
-
#
|
305
|
-
def has_field_errors?
|
306
|
-
error.field_errors.any?
|
307
|
-
end
|
308
|
-
|
309
|
-
##
|
310
|
-
# Set debugging information on the error payload
|
311
|
-
#
|
312
|
-
# @param [String] detail A string message that represents debugging information
|
313
|
-
# @param [Array<String>] stack_trace An array of strings that contain the backtrace
|
314
|
-
#
|
315
|
-
def set_debug_info(detail, stack_trace = [])
|
316
|
-
error.set_debug_info(detail, stack_trace)
|
317
|
-
end
|
318
|
-
|
319
|
-
##
|
320
|
-
# @return [Gruf::Error] The generated gruf error object
|
321
|
-
#
|
322
|
-
def error
|
323
|
-
@error ||= Gruf::Error.new
|
324
|
-
end
|
325
|
-
|
326
|
-
##
|
327
|
-
# Cleanup after a service call
|
328
|
-
#
|
329
|
-
def cleanup!
|
330
|
-
remove_instance_variable(:@error) if instance_variable_defined?(:@error)
|
331
|
-
end
|
332
|
-
end
|
333
|
-
end
|