gruf 2.4.1 → 2.4.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1289ff979cec29b1c475fc7fb9292d3eab752229e5147b59f18c107fb34531d
4
- data.tar.gz: 55acd4dee980cd8274edbbc7308edc63e09b6a4b19e4a87a6d1d1e72b11dd46f
3
+ metadata.gz: bef9466a137b8d52bc76a4d24c65fef26b0701cff21eefb2ae9811e020dd619c
4
+ data.tar.gz: f3209bfefd0e3a7fe7ee03b6bcc7a417974593b924966521346d095d87de6d5d
5
5
  SHA512:
6
- metadata.gz: 99959b15a10222393883ac16b80c8550ba35190aa9a9858764687e4349d04db9f696d37fe9ed7fd7bf4db0df8e1841791760eb49de7633392720fe9f8175d733
7
- data.tar.gz: 22f6f6f2b9db9bea6768b1f3089c6502d02323e012efdad113becd430a94af4136d8d6f216d4e73079e66d59490ee379c6ba962d1c3f9f9649243fa0b382b57d
6
+ metadata.gz: 906fa455028407ea0ac54dceeb89c54b032ddf9e1090e85d14dabf8496aad91b22d19056fdf8e84d9836399518198ed7afffa50c1cc69ac9d8a4e5a43e53f40b
7
+ data.tar.gz: c3ec65443321ff6ac00b839bf3b6a9fed748e5f7ab2ec73ffd4476d1b4b7590ccd2d865ac4f5c6703a59c5ae89746b2964f58ee43e56c62a3df62e8bddae9271
@@ -2,6 +2,20 @@ Changelog for the gruf gem. This includes internal history before the gem was ma
2
2
 
3
3
  ### Pending release
4
4
 
5
+ ### 2.4.2
6
+
7
+ - Added error handling for GRPC::Core::CallError, a low-level error in the grpc library that does not inherit
8
+ from StandardError. [#59]
9
+ - Removed `Thread.abort\_on\_exception = true`. Exceptions should be handled by gruf or the application,
10
+ and should not cause the server process to crash. [#59]
11
+ - Added guard for size of trailing metadata attached to grpc call. The default max for http2 trailing metadata
12
+ in the gRPC C library is 8kb. If we go over that limit (either through custom metadata attached to the
13
+ error by the application, or via the error payload encoded by the error serializer), the gRPC library
14
+ will throw RESOURCE\_EXHAUSTED. Gruf now detects this case, and attempts to prevent it by logging the
15
+ original error and substituting it with an internal error indicating that the metadata was too large. [#60]
16
+ - Truncate stack trace in error payload to help avoid overflowing the trailing metadata. Added backtrace\_limit
17
+ configuration parameter, which defaults to 10.[#60]
18
+
5
19
  ### 2.4.1
6
20
 
7
21
  - Safer configuration of GRPC::RpcServer. From now on, use `Gruf.rpc_server_options` for the params
@@ -12,8 +26,8 @@ Changelog for the gruf gem. This includes internal history before the gem was ma
12
26
 
13
27
  ### 2.4.0
14
28
 
15
- - Added a hash of error log levels to RequestLogging interceptor, mapping error code to level of logging to use. To
16
- override the level of logging per error response, provide a map of codes to log level in options, key :log_levels.
29
+ - Added a hash of error log levels to RequestLogging interceptor, mapping error code to level of logging to use. To
30
+ override the level of logging per error response, provide a map of codes to log level in options, key :log_levels.
17
31
  The default is :error log level.
18
32
 
19
33
  ### 2.3.0
@@ -28,7 +42,7 @@ The default is :error log level.
28
42
 
29
43
  ### 2.2.1
30
44
 
31
- - Now changes proc title once server is ready to process incoming requests [#44]
45
+ - Now changes proc title once server is ready to process incoming requests [#44]
32
46
  - Gruf now requires gRPC 1.10.x+ due to various fixes and improvements in the gRPC core libraries
33
47
 
34
48
  ### 2.2.0
@@ -37,13 +51,13 @@ The default is :error log level.
37
51
 
38
52
  ### 2.1.1
39
53
 
40
- - Add ability to pass in client stub options into Gruf::Client
54
+ - Add ability to pass in client stub options into Gruf::Client
41
55
 
42
56
  ### 2.1.0
43
57
 
44
58
  - Add ability to list, clear, insert before, insert after, and remove to a server's interceptor
45
59
  registry
46
- - Ensure interceptors and services cannot be adjusted on the server after it starts to
60
+ - Ensure interceptors and services cannot be adjusted on the server after it starts to
47
61
  prevent threading issues
48
62
  - [#36], [#37] Adds `response_class`, `request_class`, and `service` accessors to controller request
49
63
 
@@ -106,22 +120,22 @@ Gruf 2.0 is a major shift from Gruf 1.0. See [UPGRADING.md](UPGRADING.md) for de
106
120
  - Instrumentation hooks now execute similarly to outer_around hooks; they can
107
121
  now instrument failures
108
122
  - Instrumentation hooks now pass a `RequestContext` object that contains information
109
- about the incoming request, instead of relying on instance variables
123
+ about the incoming request, instead of relying on instance variables
110
124
  - StatsD hook now sends success/failure metrics for endpoints
111
125
  - Add ability to turn off sending exception message on uncaught exception.
112
126
  - Add configuration to set the error message when an uncaught exception is
113
127
  handled by gruf.
114
- - Add a request logging hook for Rails-style request logging, with optional
115
- parameter logging, blacklists, and formatter support
128
+ - Add a request logging hook for Rails-style request logging, with optional
129
+ parameter logging, blacklists, and formatter support
116
130
  - Optimizations around Symbol casting within service calls
117
131
 
118
132
  ### 1.1.0
119
133
 
120
- - Add the ability for call options to the client, which enables deadline setting
134
+ - Add the ability for call options to the client, which enables deadline setting
121
135
 
122
136
  ### 1.0.0
123
137
 
124
- - Bump gRPC to 1.4
138
+ - Bump gRPC to 1.4
125
139
 
126
140
  ### 0.14.2
127
141
 
@@ -150,7 +164,7 @@ Gruf 2.0 is a major shift from Gruf 1.0. See [UPGRADING.md](UPGRADING.md) for de
150
164
  ### 0.12.0
151
165
 
152
166
  - Add ability to run multiple around hooks
153
- - Fix bug with error handling that caused error messages to repeat across streams
167
+ - Fix bug with error handling that caused error messages to repeat across streams
154
168
 
155
169
  ### 0.11.5
156
170
 
data/README.md CHANGED
@@ -87,9 +87,9 @@ end
87
87
 
88
88
  ::Gruf::Client.new(
89
89
  service: ::Demo::ThingService,
90
- client_options: [
90
+ client_options: {
91
91
  interceptors: [MyInterceptor.new]
92
- ])
92
+ })
93
93
  ```
94
94
 
95
95
  The `interceptors` option in `client_options` can accept either a `GRPC::ClientInterceptor` class or a
@@ -239,9 +239,11 @@ For the client, you'll need to point to the public certificate:
239
239
  ```ruby
240
240
  ::Gruf::Client.new(
241
241
  service: Demo::ThingService,
242
- ssl_certificate: 'x509 public certificate here',
243
- # OR
244
- ssl_certificate_file: '/path/to/my.crt'
242
+ options: {
243
+ ssl_certificate: 'x509 public certificate here',
244
+ # OR
245
+ ssl_certificate_file: '/path/to/my.crt'
246
+ }
245
247
  )
246
248
  ```
247
249
 
@@ -485,6 +487,8 @@ gruf that you can use today:
485
487
 
486
488
  * [gruf-zipkin](https://github.com/bigcommerce/gruf-zipkin) - Provides a [Zipkin](https://zipkin.io)
487
489
  integration
490
+ * [gruf-lightstep](https://github.com/bigcommerce/gruf-lightstep) - Provides a seamless
491
+ [LightStep](https://lightstep.com) integration
488
492
  * [gruf-circuit-breaker](https://github.com/bigcommerce/gruf-circuit-breaker) - Circuit breaker
489
493
  support for services
490
494
  * [gruf-profiler](https://github.com/bigcommerce/gruf-profiler) - Profiles and provides memory usage
@@ -36,6 +36,7 @@ module Gruf
36
36
  append_server_errors_to_trailing_metadata: true,
37
37
  use_default_interceptors: true,
38
38
  backtrace_on_error: false,
39
+ backtrace_limit: 10,
39
40
  use_exception_message: true,
40
41
  internal_error_message: 'Internal Server Error',
41
42
  event_listener_proc: nil,
@@ -71,8 +71,8 @@ module Gruf
71
71
  send(method_key, &block)
72
72
  end
73
73
  rescue GRPC::BadStatus
74
- raise # passthrough
75
- rescue StandardError => e
74
+ raise # passthrough, to be caught by Gruf::Interceptors::Timer
75
+ rescue GRPC::Core::CallError, StandardError => e # CallError is not a StandardError
76
76
  set_debug_info(e.message, e.backtrace) if Gruf.backtrace_on_error
77
77
  error_message = Gruf.use_exception_message ? e.message : Gruf.internal_error_message
78
78
  fail!(:internal, :unknown, error_message)
@@ -50,6 +50,13 @@ module Gruf
50
50
  data_loss: GRPC::DataLoss
51
51
  }.freeze
52
52
 
53
+ # Default limit on trailing metadata is 8KB. We need to be careful
54
+ # not to overflow this limit, or the response message will never
55
+ # be sent. Instead, resource_exhausted will be thrown.
56
+ MAX_METADATA_SIZE = 7.5 * 1_024
57
+ METADATA_SIZE_EXCEEDED_CODE = 'metadata_size_exceeded'.freeze
58
+ METADATA_SIZE_EXCEEDED_MSG = 'Metadata too long, risks exceeding http2 trailing metadata limit.'.freeze
59
+
53
60
  # @return [Symbol] The given internal gRPC code for the error
54
61
  attr_accessor :code
55
62
  # @return [Symbol] An arbitrary application code that can be used for logical processing of the error by the client
@@ -58,8 +65,8 @@ module Gruf
58
65
  attr_accessor :message
59
66
  # @return [Array] An array of field errors that can be returned by the server
60
67
  attr_accessor :field_errors
61
- # @return [Object] A hash of debugging information, such as a stack trace and exception name, that can be used to
62
- # debug an given error response. This is sent by the server over the trailing metadata.
68
+ # @return [Errors::DebugInfo] A object containing debugging information, such as a stack trace and exception name,
69
+ # that can be used to debug an given error response. This is sent by the server over the trailing metadata.
63
70
  attr_accessor :debug_info
64
71
  # @return [GRPC::BadStatus] The gRPC BadStatus error object that was generated
65
72
  attr_writer :grpc_error
@@ -72,10 +79,11 @@ module Gruf
72
79
  # @param [Hash] args (Optional) An optional hash of arguments that will set fields on the error object
73
80
  #
74
81
  def initialize(args = {})
82
+ @field_errors = []
83
+ @metadata = {}
75
84
  args.each do |k, v|
76
85
  send("#{k}=", v) if respond_to?(k)
77
86
  end
78
- @field_errors = []
79
87
  end
80
88
 
81
89
  ##
@@ -130,16 +138,30 @@ module Gruf
130
138
  end
131
139
 
132
140
  ##
133
- # Append any appropriate errors to the gRPC call and properly update the output metadata
141
+ # Update the trailing metadata on the given gRPC call, including the error payload if configured
142
+ # to do so.
134
143
  #
135
144
  # @param [GRPC::ActiveCall] active_call The marshalled gRPC call
136
- # @return [Error] Return the error itself with the GRPC::ActiveCall attached and error metadata appended
145
+ # @return [Error] Return the error itself after updating metadata on the given gRPC call.
146
+ # In the case of a metadata overflow error, we replace the current error with
147
+ # a new one that won't cause a low-level http2 error.
137
148
  #
138
149
  def attach_to_call(active_call)
139
150
  metadata[Gruf.error_metadata_key.to_sym] = serialize if Gruf.append_server_errors_to_trailing_metadata
140
- if !metadata.empty? && active_call && active_call.respond_to?(:output_metadata)
141
- active_call.output_metadata.update(metadata)
151
+ return self if metadata.empty? || !active_call || !active_call.respond_to?(:output_metadata)
152
+
153
+ # Check if we've overflown the maximum size of output metadata. If so,
154
+ # log a warning and replace the metadata with something smaller to avoid
155
+ # resource exhausted errors.
156
+ if metadata.inspect.size > MAX_METADATA_SIZE
157
+ code = METADATA_SIZE_EXCEEDED_CODE
158
+ msg = METADATA_SIZE_EXCEEDED_MSG
159
+ logger.warn "#{code}: #{msg} Original error: #{to_h.inspect}"
160
+ err = Gruf::Error.new(code: :internal, app_code: code, message: msg)
161
+ return err.attach_to_call(active_call)
142
162
  end
163
+
164
+ active_call.output_metadata.update(metadata)
143
165
  self
144
166
  end
145
167
 
@@ -30,7 +30,12 @@ module Gruf
30
30
  #
31
31
  def initialize(detail, stack_trace = [])
32
32
  @detail = detail
33
- @stack_trace = stack_trace.is_a?(String) ? stack_trace.split("\n") : stack_trace
33
+ @stack_trace = (stack_trace.is_a?(String) ? stack_trace.split("\n") : stack_trace)
34
+
35
+ # Limit the size of the stack trace to reduce risk of overflowing metadata
36
+ stack_trace_limit = Gruf.backtrace_limit.to_i
37
+ stack_trace_limit = 10 if stack_trace_limit < 0
38
+ @stack_trace = @stack_trace[0..stack_trace_limit] if stack_trace_limit > 0
34
39
  end
35
40
 
36
41
  ##
@@ -203,8 +203,6 @@ module Gruf
203
203
  #
204
204
  # :nocov:
205
205
  def setup_signal_handlers
206
- Thread.abort_on_exception = true
207
-
208
206
  Signal.trap('INT') do
209
207
  @stop_server = true
210
208
  @stop_server_cv.broadcast
@@ -14,5 +14,5 @@
14
14
  # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
15
  #
16
16
  module Gruf
17
- VERSION = '2.4.1'.freeze
17
+ VERSION = '2.4.2'.freeze
18
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gruf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1
4
+ version: 2.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shaun McCormick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-07 00:00:00.000000000 Z
11
+ date: 2018-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler