gruf 2.8.1 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9118663c1224b49c07fe40743b6766121b1be507301e4ca64f2f3e7ef18a5b25
4
- data.tar.gz: 2025ab3f6f93b8c13bdb983e869a003415d3933340e94f15eb866d65826f954b
3
+ metadata.gz: d00ffbd4089fa41fd29adb1848564ee695725576045f447255173ebb170df586
4
+ data.tar.gz: 55c8ca35a37cae3e5c03bec59c1073fe40e3ed919586cb33bdfd83dad7da2b54
5
5
  SHA512:
6
- metadata.gz: ffd6e423548aeb8785e7063618875298b9f13570e8e1fc6b5cf24d2426059d4e98c9d3414f179a4fd071d6b4263f279666c38ca2439dfa0e7937cc2dfa79af84
7
- data.tar.gz: 5ee7fbe4964edbda7b90192ff5432a3d61897d08896a84676ae19d5c105aab6287c48f6c02368a10c0e75d9eaa1e784f8748564cc86dc2c7bf0762106b27b4fe
6
+ metadata.gz: 44acc6b979feb388fc7fee273848d36b8bb4db4228d7fab6b678ab2ed69b90742e927705c1982643f23a4170be8e8918a1cab96beb146071f191871f39c54bcc
7
+ data.tar.gz: cf79b333165e7eb458a44c9f09b8069135ff7c2fa7041193abbdd0af7fcf5ff20dd2e45ffeec94d036aa7822f2c8fffd3f3c969a2d41fcf3fbd17f1181c8ebe4
data/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@ Changelog for the gruf gem. This includes internal history before the gem was ma
2
2
 
3
3
  ### Pending release
4
4
 
5
+ ### 2.11.0
6
+
7
+ - Restrict grpc gem to <= 1.41.0 due to regressions in grpc 1.42.x
8
+ - Fallback to stdout logger at INFO if no logger is setup
9
+ - Better handling of namespace collisions with Rails
10
+ - Add `GRPC_SERVER_HOST` and `GRPC_SERVER_PORT` for ENV configuration of the server host+port
11
+ - Add `GRPC_BACKTRACE_ON_ERROR` as available ENV configuration
12
+ - Add default ENV-based configuration of the GRPC server pool
13
+ - `GRPC_SERVER_POOL_SIZE` - sets the size of the GRPC server pool
14
+ - `GRPC_SERVER_POOL_KEEP_ALIVE` - keep alive time for threads spawned by the server pool
15
+ - `GRPC_SERVER_POLL_PERIOD` - period in seconds to poll for workers in the gRPC server pool
16
+ - Improve Yardoc support across the library
17
+ - Added attribute-based documentation for Gruf configuration options
18
+ - Add mfa required for gemspec metadata
19
+
20
+ ### 2.10.0
21
+
22
+ - Drop support for Ruby 2.4/2.5 to align with Ruby EOL schedule, supporting 2.6+ only
23
+ - Allow for float/TimeSpec timeout values on clients
24
+
25
+ ### 2.9.1
26
+
27
+ - Allow for float/TimeSpec timeout values on clients (backport from 2.10.0)
28
+
29
+ ### 2.9.0
30
+
31
+ - Change to racially neutral terminology across library
32
+ - blacklist->blocklist
33
+ - master->main branch
34
+ - Explicitly declare development dependencies in gemspec
35
+ - Add script/e2e test for full e2e test in regression suite
36
+ - Explicitly declare [json gem](https://rubygems.org/gems/json) dependency
37
+ - Update to Rubocop 1.4, add in rubocop-rspec for spec tests
38
+ - Add Ruby 2.7, 3.0 support
39
+
5
40
  ### 2.8.1
6
41
 
7
42
  - Fix issue with --suppress-default-interceptors not working [#95]
@@ -145,11 +180,11 @@ Gruf 2.0 is a major shift from Gruf 1.0. See [UPGRADING.md](UPGRADING.md) for de
145
180
  ### 1.2.4
146
181
 
147
182
  - Loosen explicit Protobuf dependency now that 3.4.0.2 is released
148
- - Guard against nil params in logger blacklist
183
+ - Guard against nil params in logger blocklist
149
184
 
150
185
  ### 1.2.3
151
186
 
152
- - Support nested blacklist parameters in path.to.key format
187
+ - Support nested blocklist parameters in path.to.key format
153
188
 
154
189
  ### 1.2.2
155
190
 
@@ -171,7 +206,7 @@ Gruf 2.0 is a major shift from Gruf 1.0. See [UPGRADING.md](UPGRADING.md) for de
171
206
  - Add configuration to set the error message when an uncaught exception is
172
207
  handled by gruf.
173
208
  - Add a request logging hook for Rails-style request logging, with optional
174
- parameter logging, blacklists, and formatter support
209
+ parameter logging, blocklists, and formatter support
175
210
  - Optimizations around Symbol casting within service calls
176
211
 
177
212
  ### 1.1.0
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # gruf - gRPC Ruby Framework
2
2
 
3
- [![CircleCI](https://circleci.com/gh/bigcommerce/gruf/tree/master.svg?style=svg)](https://circleci.com/gh/bigcommerce/gruf/tree/master) [![Gem Version](https://badge.fury.io/rb/gruf.svg)](https://badge.fury.io/rb/gruf) [![Documentation](https://inch-ci.org/github/bigcommerce/gruf.svg?branch=master)](https://inch-ci.org/github/bigcommerce/gruf?branch=master)
3
+ [![CircleCI](https://circleci.com/gh/bigcommerce/gruf/tree/main.svg?style=svg)](https://circleci.com/gh/bigcommerce/gruf/tree/main) [![Gem Version](https://badge.fury.io/rb/gruf.svg)](https://badge.fury.io/rb/gruf) [![Documentation](https://inch-ci.org/github/bigcommerce/gruf.svg?branch=main)](https://inch-ci.org/github/bigcommerce/gruf?branch=main)
4
4
 
5
5
  gruf is a Ruby framework that wraps the [gRPC Ruby library](https://github.com/grpc/grpc/tree/master/src/ruby) to
6
6
  provide a more streamlined integration into Ruby and Ruby on Rails applications.
@@ -17,7 +17,7 @@ up fast and efficiently at scale. Some of its features include:
17
17
  still preserving gRPC BadStatus codes
18
18
  * Server and client execution timings in responses
19
19
 
20
- gruf currently has active support for gRPC 1.10.x+. gruf is compatible and tested with Ruby 2.2-2.6.
20
+ gruf currently has active support for gRPC 1.10.x+. gruf is compatible and tested with Ruby 2.2-3.0.
21
21
  gruf is also not [Rails](https://github.com/rails/rails)-specific, and can be used in any Ruby framework
22
22
  (such as [Grape](https://github.com/ruby-grape/grape) or [dry-rb](https://dry-rb.org/), for instance).
23
23
 
data/gruf.gemspec CHANGED
@@ -15,7 +15,7 @@
15
15
  # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
16
  # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
17
  #
18
- $:.push File.expand_path("../lib", __FILE__)
18
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
19
19
  require 'gruf/version'
20
20
 
21
21
  Gem::Specification.new do |spec|
@@ -30,19 +30,38 @@ Gem::Specification.new do |spec|
30
30
  spec.homepage = 'https://github.com/bigcommerce/gruf'
31
31
 
32
32
  spec.files = Dir['README.md', 'CHANGELOG.md', 'CODE_OF_CONDUCT.md', 'lib/**/*', 'gruf.gemspec']
33
- spec.executables << 'gruf'
33
+ spec.executables << 'gruf'
34
34
  spec.require_paths = ['lib']
35
35
 
36
- spec.required_ruby_version = '~> 2.4'
36
+ spec.required_ruby_version = '>= 2.6', '< 3.1'
37
37
 
38
- spec.add_development_dependency 'bundler', '~> 1.11'
38
+ spec.metadata['rubygems_mfa_required'] = 'true'
39
+
40
+ spec.add_development_dependency 'bundler-audit', '>= 0.6'
41
+ # rubocop:disable Gemspec/RubyVersionGlobalsUsage
42
+ spec.add_development_dependency(
43
+ 'factory_bot',
44
+ (Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5') ? '>= 6.1' : '~> 5.2')
45
+ )
46
+ # rubocop:enable Gemspec/RubyVersionGlobalsUsage
47
+ spec.add_development_dependency 'ffaker', '>= 2.15'
48
+ spec.add_development_dependency 'pry', '~> 0.12'
49
+ spec.add_development_dependency 'pry-byebug', '>= 3.9'
39
50
  spec.add_development_dependency 'rake', '>= 10.0'
40
- spec.add_development_dependency 'pry', '~> 0.11'
51
+ spec.add_development_dependency 'rspec', '>= 3.8'
52
+ spec.add_development_dependency 'rspec_junit_formatter', '>= 0.4'
53
+ spec.add_development_dependency 'rubocop', '>= 1.0'
54
+ spec.add_development_dependency 'rubocop-performance', '>= 0.0.1'
55
+ spec.add_development_dependency 'rubocop-rspec', '>= 2.0'
56
+ spec.add_development_dependency 'rubocop-thread_safety', '>= 0.3'
57
+ spec.add_development_dependency 'simplecov', '>= 0.16'
41
58
 
42
- spec.add_runtime_dependency 'grpc', '~> 1.10'
43
- spec.add_runtime_dependency 'grpc-tools', '~> 1.10'
44
59
  spec.add_runtime_dependency 'activesupport', '> 4'
45
-
46
60
  spec.add_runtime_dependency 'concurrent-ruby', '> 1'
47
- spec.add_runtime_dependency 'slop', '~> 4.6'
61
+ spec.add_runtime_dependency 'e2mmap', '>= 0.1'
62
+ spec.add_runtime_dependency 'grpc', '~> 1.10', '<= 1.41.0'
63
+ spec.add_runtime_dependency 'grpc-tools', '~> 1.10', '<= 1.41.0'
64
+ spec.add_runtime_dependency 'json', '>= 2.3'
65
+ spec.add_runtime_dependency 'slop', '>= 4.6'
66
+ spec.add_runtime_dependency 'thwait', '>= 0.1'
48
67
  end
@@ -38,7 +38,7 @@ module Gruf
38
38
  @services = services || Gruf.services
39
39
  @hook_executor = hook_executor || Gruf::Hooks::Executor.new(hooks: Gruf.hooks&.prepare)
40
40
  @server = server || Gruf::Server.new(Gruf.server_options)
41
- @logger = logger || Gruf.logger || ::Logger.new(STDERR)
41
+ @logger = logger || Gruf.logger || ::Logger.new($stderr)
42
42
  end
43
43
 
44
44
  ##
@@ -23,7 +23,8 @@ module Gruf
23
23
  # GRPC::BadStatus error
24
24
  #
25
25
  class Error < StandardError
26
- # @return [Object] error The deserialized error
26
+ # @!attribute [r] error
27
+ # @return [Object] error The deserialized error
27
28
  attr_reader :error
28
29
 
29
30
  ##
@@ -33,6 +34,7 @@ module Gruf
33
34
  #
34
35
  def initialize(error)
35
36
  @error = error
37
+ super
36
38
  end
37
39
  end
38
40
 
@@ -57,6 +59,7 @@ module Gruf
57
59
  class FailedPrecondition < Error; end
58
60
  class Internal < Error; end
59
61
  class PermissionDenied < Error; end
62
+ class ResourceExhausted < Error; end
60
63
  class Unauthenticated < Error; end
61
64
  class Unavailable < Error; end
62
65
  class Unimplemented < Error; end
data/lib/gruf/client.rb CHANGED
@@ -38,11 +38,14 @@ module Gruf
38
38
  class Client < SimpleDelegator
39
39
  include Gruf::Loggable
40
40
 
41
- # @return [Class] The base, friendly name of the service being requested
41
+ # @!attribute [r] base_klass
42
+ # @return [Class] The base, friendly name of the service being requested
42
43
  attr_reader :base_klass
43
- # @return [Class] The class name of the gRPC service being requested
44
+ # @!attribute [r] service_klass
45
+ # @return [Class] The class name of the gRPC service being requested
44
46
  attr_reader :service_klass
45
- # @return [Hash] A hash of options for the client
47
+ # @!attribute [r] opts
48
+ # @return [Hash] A hash of options for the client
46
49
  attr_reader :opts
47
50
 
48
51
  ##
@@ -62,8 +65,8 @@ module Gruf
62
65
  @opts[:hostname] = @opts.fetch(:hostname, Gruf.default_client_host)
63
66
  @opts[:channel_credentials] = @opts.fetch(:channel_credentials, Gruf.default_channel_credentials)
64
67
  @error_factory = Gruf::Client::ErrorFactory.new
65
- client_options[:timeout] = client_options[:timeout].to_i if client_options.key?(:timeout)
66
- client = "#{service}::Stub".constantize.new(@opts[:hostname], build_ssl_credentials, client_options)
68
+ client_options[:timeout] = parse_timeout(client_options[:timeout]) if client_options.key?(:timeout)
69
+ client = "#{service}::Stub".constantize.new(@opts[:hostname], build_ssl_credentials, **client_options)
67
70
  super(client)
68
71
  end
69
72
 
@@ -216,5 +219,27 @@ module Gruf
216
219
  Gruf::Serializers::Errors::Json
217
220
  end
218
221
  end
222
+
223
+ ##
224
+ # Handle various timeout values and prevent improper value setting
225
+ #
226
+ # @see GRPC::Core::TimeConsts#from_relative_time
227
+ # @param [mixed] timeout
228
+ # @return [Float]
229
+ # @return [GRPC::Core::TimeSpec]
230
+ #
231
+ def parse_timeout(timeout)
232
+ if timeout.nil?
233
+ GRPC::Core::TimeConsts::ZERO
234
+ elsif timeout.is_a?(GRPC::Core::TimeSpec)
235
+ timeout
236
+ elsif timeout.is_a?(Numeric) # rubocop:disable Lint/DuplicateBranch
237
+ timeout
238
+ elsif timeout.respond_to?(:to_f)
239
+ timeout.to_f
240
+ else
241
+ raise ArgumentError, 'timeout is not a valid value: does not respond to to_f'
242
+ end
243
+ end
219
244
  end
220
245
  end
@@ -20,6 +20,63 @@ module Gruf
20
20
  # Represents configuration settings for the system
21
21
  #
22
22
  module Configuration
23
+ # @!attribute root_path
24
+ # @return [String] The root path for your application
25
+ # @!attribute server_binding_url
26
+ # @return [String] The full hostname:port that the gRPC server should bind to
27
+ # @!attribute server_options
28
+ # @return [Hash] A hash of options to pass to the server instance
29
+ # @!attribute interceptors
30
+ # @return [::Gruf::Interceptors::Registry] A registry of Gruf server interceptors
31
+ # @!attribute hooks
32
+ # @return [::Gruf::Hooks::Registry] A registry of Gruf hooks for the server
33
+ # @!attribute default_channel_credentials
34
+ # @return [NilClass]
35
+ # @return [Symbol]
36
+ # @return [Hash]
37
+ # @!attribute default_client_host
38
+ # @return [String] The default host for all new Gruf::Client objects to use as their target host
39
+ # @!attribute use_ssl
40
+ # @return [Boolean] If true, will setup the server to use TLS
41
+ # @!attribute ssl_crt_file
42
+ # @return [String] If use_ssl is true, the relative path from the root_path to the CRT file for the server
43
+ # @!attribute ssl_key_file
44
+ # @return [String] If use_ssl is true, the relative path from the root_path to the key file for the server
45
+ # @!attribute controllers_path
46
+ # @return [String] The relative path from root_path to locate Gruf Controllers in
47
+ # @!attribute services
48
+ # @return [Array<Class>] An array of services to serve with this Gruf server
49
+ # @!attribute logger
50
+ # @return [Logger] The logger class for Gruf-based logging
51
+ # @!attribute grpc_logger
52
+ # @return [Logger] The logger to use with GRPC's core logger (which logs plaintext). It is recommended to set
53
+ # this to an STDOUT logger and use a logging pipeline that can translate plaintext logs given GRPC's
54
+ # unformatted logging.
55
+ # @!attribute error_metadata_key
56
+ # @return [Symbol] The metadata key to use for error messages sent back in trailing metadata.
57
+ # @!attribute error_serializer
58
+ # @return [NilClass|::Gruf::Serializers::Errors::Base] The error serializer to use for error messages sent
59
+ # back in trailing metadata. Defaults to the base JSON serializer.
60
+ # @!attribute append_server_errors_to_trailing_metadata
61
+ # @return [Boolean] If true, will append all server error information into the trailing metadata in the response
62
+ # from the server
63
+ # @!attribute use_default_interceptors
64
+ # @return [Boolean] If true, will use the default ActiveRecord and Timer interceptors for servers
65
+ # @!attribute backtrace_on_error
66
+ # @return [Boolean] If true, will return the backtrace on any errors in servers in the trailing metadata
67
+ # @!attribute backtrace_limit
68
+ # @return [Integer] The limit of lines to use in backtraces returned
69
+ # @!attribute use_exception_message
70
+ # @return [String] If true, will pass the actual exception message from the error in a server
71
+ # @!attribute internal_error_message
72
+ # @return [String] If use_exception_message is false, this message will be used instead as a replacement
73
+ # @!attribute event_listener_proc
74
+ # @return [NilClass]
75
+ # @return [Proc] If set, this will be used during GRPC events (such as pool exhaustions)
76
+ # @!attribute synchronized_client_internal_cache_expiry
77
+ # @return [Integer] Internal cache expiry period (in seconds) for the SynchronizedClient
78
+ # @!attribute rpc_server_options
79
+ # @return [Hash] A hash of RPC options for GRPC server configuration
23
80
  VALID_CONFIG_KEYS = {
24
81
  root_path: '',
25
82
  server_binding_url: '0.0.0.0:9001',
@@ -61,8 +118,8 @@ module Gruf
61
118
  # Whenever this is extended into a class, setup the defaults
62
119
  #
63
120
  def self.extended(base)
64
- if defined?(Rails)
65
- Gruf::Integrations::Rails::Railtie.config.before_initialize { base.reset }
121
+ if defined?(::Rails)
122
+ ::Gruf::Integrations::Rails::Railtie.config.before_initialize { base.reset }
66
123
  else
67
124
  base.reset
68
125
  end
@@ -98,24 +155,30 @@ module Gruf
98
155
  #
99
156
  def reset
100
157
  VALID_CONFIG_KEYS.each do |k, v|
101
- send((k.to_s + '='), v)
158
+ send("#{k}=", v)
102
159
  end
103
- self.interceptors = Gruf::Interceptors::Registry.new
104
- self.hooks = Gruf::Hooks::Registry.new
105
- self.root_path = Rails.root.to_s.chomp('/') if defined?(Rails)
106
- if defined?(Rails) && Rails.logger
107
- self.logger = Rails.logger
108
- else
109
- require 'logger'
110
- self.logger = ::Logger.new(STDOUT)
111
- end
112
- self.grpc_logger = logger if grpc_logger.nil?
160
+ self.server_binding_url = "#{::ENV.fetch('GRPC_SERVER_HOST',
161
+ '0.0.0.0')}:#{::ENV.fetch('GRPC_SERVER_PORT', 9_001)}"
162
+ self.interceptors = ::Gruf::Interceptors::Registry.new
163
+ self.hooks = ::Gruf::Hooks::Registry.new
164
+ self.root_path = ::Rails.root.to_s.chomp('/') if defined?(::Rails)
165
+ determine_loggers
113
166
  self.ssl_crt_file = "#{root_path}config/ssl/#{environment}.crt"
114
167
  self.ssl_key_file = "#{root_path}config/ssl/#{environment}.key"
115
168
  self.controllers_path = root_path.to_s.empty? ? 'app/rpc' : "#{root_path}/app/rpc"
169
+ self.backtrace_on_error = ::ENV.fetch('GRPC_BACKTRACE_ON_ERROR', 0).to_i.positive?
170
+ self.rpc_server_options = {
171
+ max_waiting_requests: ::ENV.fetch('GRPC_SERVER_MAX_WAITING_REQUESTS',
172
+ GRPC::RpcServer::DEFAULT_MAX_WAITING_REQUESTS).to_i,
173
+ pool_size: ::ENV.fetch('GRPC_SERVER_POOL_SIZE', GRPC::RpcServer::DEFAULT_POOL_SIZE).to_i,
174
+ pool_keep_alive: ::ENV.fetch('GRPC_SERVER_POOL_KEEP_ALIVE', GRPC::Pool::DEFAULT_KEEP_ALIVE),
175
+ poll_period: ::ENV.fetch('GRPC_SERVER_POLL_PERIOD', GRPC::RpcServer::DEFAULT_POLL_PERIOD),
176
+ connect_md_proc: nil,
177
+ server_args: {}
178
+ }
116
179
  if use_default_interceptors
117
- interceptors.use(Gruf::Interceptors::ActiveRecord::ConnectionReset)
118
- interceptors.use(Gruf::Interceptors::Instrumentation::OutputMetadataTimer)
180
+ interceptors.use(::Gruf::Interceptors::ActiveRecord::ConnectionReset)
181
+ interceptors.use(::Gruf::Interceptors::Instrumentation::OutputMetadataTimer)
119
182
  end
120
183
  options
121
184
  end
@@ -128,11 +191,30 @@ module Gruf
128
191
  # @return [String] The current Ruby environment
129
192
  #
130
193
  def environment
131
- if defined?(Rails)
132
- Rails.env.to_s
194
+ if defined?(::Rails)
195
+ ::Rails.env.to_s
133
196
  else
134
197
  (ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development').to_s
135
198
  end
136
199
  end
200
+
201
+ ##
202
+ # Dynamically determine the appropriate logger
203
+ #
204
+ def determine_loggers
205
+ if defined?(::Rails) && ::Rails.logger
206
+ self.logger = ::Rails.logger
207
+ else
208
+ require 'logger'
209
+ self.logger = ::Logger.new($stdout)
210
+ log_level = ::ENV.fetch('LOG_LEVEL', 'info').to_s.upcase
211
+ begin
212
+ logger.level = ::Logger::Severity.const_get(log_level)
213
+ rescue NameError => _e
214
+ logger.level = ::Logger::Severity::INFO
215
+ end
216
+ end
217
+ self.grpc_logger = logger if grpc_logger.nil?
218
+ end
137
219
  end
138
220
  end
@@ -26,13 +26,16 @@ module Gruf
26
26
  class Base
27
27
  include Gruf::Errors::Helpers
28
28
 
29
- # @var [Gruf::Controller::Request] request
29
+ # @!attribute [r] request
30
+ # @return [Gruf::Controller::Request] The incoming request
30
31
  attr_reader :request
31
- # @var [Gruf::Error] error
32
+ # @!attribute [r] error
33
+ # @return [Gruf::Error] The current error on the controller
32
34
  attr_reader :error
33
35
 
34
36
  class << self
35
- # @var [GRPC::GenericService] bound_service
37
+ # @!attribute [r] bound_service
38
+ # @return [GRPC::GenericService] bound_service The bound gRPC service class
36
39
  attr_reader :bound_service
37
40
  end
38
41
 
@@ -65,7 +68,9 @@ module Gruf
65
68
  def self.bind(service)
66
69
  service_class = service.name.constantize
67
70
  Gruf.services << service_class
71
+ # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
68
72
  @bound_service = service_class
73
+ # rubocop:enable ThreadSafety/InstanceVariableInClassMethod
69
74
  ServiceBinder.new(service_class).bind!(self)
70
75
  end
71
76
 
@@ -21,15 +21,20 @@ module Gruf
21
21
  # Encapsulates a request for a controller
22
22
  #
23
23
  class Request
24
- # @var [Object] message
24
+ # @!attribute [r] message
25
+ # @return [Object] The protobuf message in the request
25
26
  attr_reader :message
26
- # @var [GRPC::ActiveCall] active_call
27
+ # @!attribute [r] active_call
28
+ # @return [GRPC::ActiveCall] The active call object used for this request
27
29
  attr_reader :active_call
28
- # @var [Symbol] method_key
30
+ # @!attribute [r] method_key
31
+ # @return [Symbol] The method name being requested
29
32
  attr_reader :method_key
30
- # @var [Gruf::Controllers::Request::Type] type
33
+ # @!attribute [r] type
34
+ # @return [Gruf::Controllers::Request::Type] The type of request
31
35
  attr_reader :type
32
- # @var [Class] service
36
+ # @!attribute [r] service
37
+ # @return [Class] The GRPC service class for this request
33
38
  attr_reader :service
34
39
 
35
40
  delegate :metadata, to: :active_call
@@ -58,7 +63,7 @@ module Gruf
58
63
  # @param [Class] service The class of the service being executed against
59
64
  # @param [GRPC::RpcDesc] rpc_desc The RPC descriptor of the call
60
65
  # @param [GRPC::ActiveCall] active_call The restricted view of the call
61
- # @param [Object] message The protobuf message (or messages) of the request
66
+ # @param [Object|Google::Protobuf::MessageExts] message The protobuf message (or messages) of the request
62
67
  #
63
68
  def initialize(method_key:, service:, rpc_desc:, active_call:, message:)
64
69
  @method_key = method_key
@@ -76,7 +81,7 @@ module Gruf
76
81
  # @return [String] The mapped service key
77
82
  #
78
83
  def service_key
79
- @service.name.underscore.tr('/', '.').gsub('.service', '')
84
+ @service.name.to_s.underscore.tr('/', '.').gsub('.service', '')
80
85
  end
81
86
 
82
87
  ##
@@ -99,21 +104,24 @@ module Gruf
99
104
  # @return [String] The parsed service method name
100
105
  #
101
106
  def method_name
102
- "#{service_key}.#{method_key}"
107
+ "#{service_key}.#{@method_key}"
103
108
  end
104
109
 
105
110
  ##
106
111
  # Return all messages for this request, properly handling different request types
107
112
  #
108
- # @return Enumerable<Object> All messages for this request
113
+ # @return [Enumerable<Object>] All messages for this request
114
+ # @return [Object] If a bidi streamed request, will return the message object
109
115
  #
110
116
  def messages
111
117
  if client_streamer?
112
- message.call { |msg| yield msg }
118
+ # rubocop:disable Style/ExplicitBlockArgument
119
+ @message.call { |msg| yield msg }
120
+ # rubocop:enable Style/ExplicitBlockArgument
113
121
  elsif bidi_streamer?
114
- message
122
+ @message
115
123
  else
116
- [message]
124
+ [@message]
117
125
  end
118
126
  end
119
127
  end
@@ -38,7 +38,7 @@ module Gruf
38
38
  ##
39
39
  # Bind all methods on the service to the passed controller
40
40
  #
41
- # @param [Gruf::Controllers::Base] controller
41
+ # @param [Class<Gruf::Controllers::Base>] controller
42
42
  #
43
43
  def bind!(controller)
44
44
  rpc_methods.each { |name, desc| bind_method(controller, name, desc) }
data/lib/gruf/error.rb CHANGED
@@ -59,20 +59,28 @@ module Gruf
59
59
  METADATA_SIZE_EXCEEDED_CODE = 'metadata_size_exceeded'
60
60
  METADATA_SIZE_EXCEEDED_MSG = 'Metadata too long, risks exceeding http2 trailing metadata limit.'
61
61
 
62
- # @return [Symbol] The given internal gRPC code for the error
62
+ # @!attribute code
63
+ # @return [Symbol] The given internal gRPC code for the error
63
64
  attr_accessor :code
64
- # @return [Symbol] An arbitrary application code that can be used for logical processing of the error by the client
65
+ # @!attribute app_code
66
+ # @return [Symbol] An arbitrary application code that can be used for logical processing of the error
67
+ # by the client
65
68
  attr_accessor :app_code
66
- # @return [String] The error message returned by the server
69
+ # @!attribute message
70
+ # @return [String] The error message returned by the server
67
71
  attr_accessor :message
68
- # @return [Array] An array of field errors that can be returned by the server
72
+ # @!attribute field_errors
73
+ # @return [Array] An array of field errors that can be returned by the server
69
74
  attr_accessor :field_errors
70
- # @return [Errors::DebugInfo] A object containing debugging information, such as a stack trace and exception name,
71
- # that can be used to debug an given error response. This is sent by the server over the trailing metadata.
75
+ # @!attribute debug_info
76
+ # @return [Errors::DebugInfo] A object containing debugging information, such as a stack trace and exception name,
77
+ # that can be used to debug an given error response. This is sent by the server over the trailing metadata.
72
78
  attr_accessor :debug_info
73
- # @return [GRPC::BadStatus] The gRPC BadStatus error object that was generated
79
+ # @!attribute [w] grpc_error
80
+ # @return [GRPC::BadStatus] The gRPC BadStatus error object that was generated
74
81
  attr_writer :grpc_error
75
- # @return [Hash] The trailing metadata that was attached to the error
82
+ # @!attribute [r] metadata
83
+ # @return [Hash] The trailing metadata that was attached to the error
76
84
  attr_reader :metadata
77
85
 
78
86
  ##
@@ -126,7 +134,7 @@ module Gruf
126
134
  # @return [Hash] The newly set metadata
127
135
  #
128
136
  def metadata=(metadata)
129
- @metadata = metadata.map { |k, str| [k, str.to_s] }.to_h
137
+ @metadata = metadata.transform_values(&:to_s)
130
138
  end
131
139
 
132
140
  ##
@@ -21,9 +21,11 @@ module Gruf
21
21
  # Represents debugging information for an exception that occurred in a gRPC service
22
22
  #
23
23
  class DebugInfo
24
- # @return [String] The detail message of the exception
24
+ # @!attribute [r] detail
25
+ # @return [String] The detail message of the exception
25
26
  attr_reader :detail
26
- # @return [Array<String>] The stack trace generated by the exception as an array of strings
27
+ # @!attribute [r] stack_trace
28
+ # @return [Array<String>] The stack trace generated by the exception as an array of strings
27
29
  attr_reader :stack_trace
28
30
 
29
31
  ##
@@ -21,11 +21,14 @@ module Gruf
21
21
  # Represents a field-specific error
22
22
  #
23
23
  class Field
24
- # @return [Symbol] The name of the field as a Symbol
24
+ # @!attribute [r] field_name
25
+ # @return [Symbol] The name of the field as a Symbol
25
26
  attr_reader :field_name
26
- # @return [Symbol] The application error code for the field, e.g. :job_not_found
27
+ # @!attribute [r] error_code
28
+ # @return [Symbol] The application error code for the field, e.g. :job_not_found
27
29
  attr_reader :error_code
28
- # @return [String] The error message for the field, e.g. "Job with ID 123 not found"
30
+ # @!attribute [r] message
31
+ # @return [String] The error message for the field, e.g. "Job with ID 123 not found"
29
32
  attr_reader :message
30
33
 
31
34
  ##
@@ -39,7 +39,7 @@ module Gruf
39
39
  @hooks.each do |hook|
40
40
  next unless hook.respond_to?(name)
41
41
 
42
- hook.send(name, arguments)
42
+ hook.send(name, **arguments)
43
43
  end
44
44
  end
45
45
  end
@@ -21,11 +21,14 @@ module Gruf
21
21
  # Base class for interception requests
22
22
  #
23
23
  class Base
24
- # @var [Gruf::Controllers::Request] request
24
+ # @!attribute [r] request
25
+ # @return [Gruf::Controllers::Request] request
25
26
  attr_reader :request
26
- # @var [Gruf::Error] error
27
+ # @!attribute [r] error
28
+ # @return [Gruf::Error] error
27
29
  attr_reader :error
28
- # @var [Hash] options
30
+ # @!attribute [r] options
31
+ # @return [Hash] options
29
32
  attr_reader :options
30
33
 
31
34
  ##