gruf 2.9.1 → 2.15.1

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.
@@ -15,9 +15,6 @@
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
- require_relative 'request'
19
- require_relative 'service_binder'
20
-
21
18
  module Gruf
22
19
  module Controllers
23
20
  ##
@@ -26,13 +23,16 @@ module Gruf
26
23
  class Base
27
24
  include Gruf::Errors::Helpers
28
25
 
29
- # @var [Gruf::Controller::Request] request
26
+ # @!attribute [r] request
27
+ # @return [Gruf::Controller::Request] The incoming request
30
28
  attr_reader :request
31
- # @var [Gruf::Error] error
29
+ # @!attribute [r] error
30
+ # @return [Gruf::Error] The current error on the controller
32
31
  attr_reader :error
33
32
 
34
33
  class << self
35
- # @var [GRPC::GenericService] bound_service
34
+ # @!attribute [r] bound_service
35
+ # @return [GRPC::GenericService] bound_service The bound gRPC service class
36
36
  attr_reader :bound_service
37
37
  end
38
38
 
@@ -64,11 +64,12 @@ module Gruf
64
64
  #
65
65
  def self.bind(service)
66
66
  service_class = service.name.constantize
67
- Gruf.services << service_class
67
+ ::Gruf.logger.debug "[gruf] Binding #{service_class} to #{name}"
68
+ ::Gruf.services << service_class
68
69
  # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
69
70
  @bound_service = service_class
70
71
  # rubocop:enable ThreadSafety/InstanceVariableInClassMethod
71
- ServiceBinder.new(service_class).bind!(self)
72
+ ServiceBinder.bind!(service: service_class, controller: self)
72
73
  end
73
74
 
74
75
  ##
@@ -89,6 +90,7 @@ module Gruf
89
90
  # @param [block] &block The passed block for executing the method
90
91
  #
91
92
  def call(method_key, &block)
93
+ ::Gruf.autoloaders.reload if ::Gruf.development?
92
94
  Interceptors::Context.new(@interceptors).intercept! do
93
95
  process_action(method_key, &block)
94
96
  end
@@ -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
@@ -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
  ##
@@ -106,6 +111,7 @@ module Gruf
106
111
  # Return all messages for this request, properly handling different request types
107
112
  #
108
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?
@@ -26,92 +26,79 @@ module Gruf
26
26
  #
27
27
  class BoundDesc < SimpleDelegator; end
28
28
 
29
- ##
30
- # Initialize a service binder instance with the given service
31
- #
32
- # @param [GRPC::GenericService] service The gRPC service stub to bind
33
- #
34
- def initialize(service)
35
- @service = service
36
- end
37
-
38
- ##
39
- # Bind all methods on the service to the passed controller
40
- #
41
- # @param [Class<Gruf::Controllers::Base>] controller
42
- #
43
- def bind!(controller)
44
- rpc_methods.each { |name, desc| bind_method(controller, name, desc) }
45
- end
46
-
47
- private
48
-
49
- ##
50
- # Bind the grpc methods to the service, allowing for server interception and execution control
51
- #
52
- # @param [Gruf::Controllers::Base] controller
53
- # @param [Symbol] method_name
54
- # @param [BoundDesc] desc
55
- #
56
- def bind_method(controller, method_name, desc)
57
- method_key = method_name.to_s.underscore.to_sym
58
- service_ref = @service
29
+ class << self
30
+ ##
31
+ # Bind all methods on the service to the passed controller
32
+ #
33
+ # @param [Class<Gruf::Controllers::Base>] controller
34
+ #
35
+ def bind!(service:, controller:)
36
+ rpc_methods = service.rpc_descs.map { |rd| BoundDesc.new(rd) }
37
+ rpc_methods.each { |name, desc| bind_method(service, controller, name, desc) }
38
+ end
59
39
 
60
- @service.class_eval do
61
- if desc.request_response?
62
- define_method(method_key) do |message, active_call|
63
- c = controller.new(
64
- method_key: method_key,
65
- service: service_ref,
66
- message: message,
67
- active_call: active_call,
68
- rpc_desc: desc
69
- )
70
- c.call(method_key)
71
- end
72
- elsif desc.client_streamer?
73
- define_method(method_key) do |active_call|
74
- c = controller.new(
75
- method_key: method_key,
76
- service: service_ref,
77
- message: proc { |&block| active_call.each_remote_read(&block) },
78
- active_call: active_call,
79
- rpc_desc: desc
80
- )
81
- c.call(method_key)
82
- end
83
- elsif desc.server_streamer?
84
- define_method(method_key) do |message, active_call, &block|
85
- c = controller.new(
86
- method_key: method_key,
87
- service: service_ref,
88
- message: message,
89
- active_call: active_call,
90
- rpc_desc: desc
91
- )
92
- c.call(method_key, &block)
93
- end
94
- else # bidi
95
- define_method(method_key) do |messages, active_call, &block|
96
- c = controller.new(
97
- method_key: method_key,
98
- service: service_ref,
99
- message: messages,
100
- active_call: active_call,
101
- rpc_desc: desc
102
- )
103
- c.call(method_key, &block)
40
+ ##
41
+ # Bind the grpc methods to the service, allowing for server interception and execution control
42
+ #
43
+ # @param [Gruf::Controllers::Base] controller
44
+ # @param [Symbol] method_name
45
+ # @param [BoundDesc] desc
46
+ #
47
+ def bind_method(service_ref, controller, method_name, desc)
48
+ method_key = method_name.to_s.underscore.to_sym
49
+ service_ref.class_eval do
50
+ if desc.request_response?
51
+ define_method(method_key) do |message, active_call|
52
+ controller = controller.name.constantize
53
+ c = controller.new(
54
+ method_key: method_key,
55
+ service: service_ref,
56
+ message: message,
57
+ active_call: active_call,
58
+ rpc_desc: desc
59
+ )
60
+ c.call(method_key)
61
+ end
62
+ elsif desc.client_streamer?
63
+ define_method(method_key) do |active_call|
64
+ controller = controller.name.constantize
65
+ c = controller.new(
66
+ method_key: method_key,
67
+ service: service_ref,
68
+ message: proc { |&block| active_call.each_remote_read(&block) },
69
+ active_call: active_call,
70
+ rpc_desc: desc
71
+ )
72
+ c.call(method_key)
73
+ end
74
+ elsif desc.server_streamer?
75
+ define_method(method_key) do |message, active_call, &block|
76
+ controller = controller.name.constantize
77
+ c = controller.new(
78
+ method_key: method_key,
79
+ service: service_ref,
80
+ message: message,
81
+ active_call: active_call,
82
+ rpc_desc: desc
83
+ )
84
+ c.call(method_key, &block)
85
+ end
86
+ else # bidi
87
+ define_method(method_key) do |messages, active_call, &block|
88
+ controller = controller.name.constantize
89
+ c = controller.new(
90
+ method_key: method_key,
91
+ service: service_ref,
92
+ message: messages,
93
+ active_call: active_call,
94
+ rpc_desc: desc
95
+ )
96
+ c.call(method_key, &block)
97
+ end
104
98
  end
105
99
  end
106
100
  end
107
101
  end
108
-
109
- ##
110
- # @return Array<Gruf::Controllers::ServiceBinder::BoundDesc>
111
- #
112
- def rpc_methods
113
- @service.rpc_descs.map { |rd| BoundDesc.new(rd) }
114
- end
115
102
  end
116
103
  end
117
104
  end
data/lib/gruf/error.rb CHANGED
@@ -15,10 +15,6 @@
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
- require_relative 'errors/field'
19
- require_relative 'errors/debug_info'
20
- require_relative 'serializers/errors/base'
21
- require_relative 'serializers/errors/json'
22
18
 
23
19
  module Gruf
24
20
  ##
@@ -59,20 +55,28 @@ module Gruf
59
55
  METADATA_SIZE_EXCEEDED_CODE = 'metadata_size_exceeded'
60
56
  METADATA_SIZE_EXCEEDED_MSG = 'Metadata too long, risks exceeding http2 trailing metadata limit.'
61
57
 
62
- # @return [Symbol] The given internal gRPC code for the error
58
+ # @!attribute code
59
+ # @return [Symbol] The given internal gRPC code for the error
63
60
  attr_accessor :code
64
- # @return [Symbol] An arbitrary application code that can be used for logical processing of the error by the client
61
+ # @!attribute app_code
62
+ # @return [Symbol] An arbitrary application code that can be used for logical processing of the error
63
+ # by the client
65
64
  attr_accessor :app_code
66
- # @return [String] The error message returned by the server
65
+ # @!attribute message
66
+ # @return [String] The error message returned by the server
67
67
  attr_accessor :message
68
- # @return [Array] An array of field errors that can be returned by the server
68
+ # @!attribute field_errors
69
+ # @return [Array] An array of field errors that can be returned by the server
69
70
  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.
71
+ # @!attribute debug_info
72
+ # @return [Errors::DebugInfo] A object containing debugging information, such as a stack trace and exception name,
73
+ # that can be used to debug an given error response. This is sent by the server over the trailing metadata.
72
74
  attr_accessor :debug_info
73
- # @return [GRPC::BadStatus] The gRPC BadStatus error object that was generated
75
+ # @!attribute [w] grpc_error
76
+ # @return [GRPC::BadStatus] The gRPC BadStatus error object that was generated
74
77
  attr_writer :grpc_error
75
- # @return [Hash] The trailing metadata that was attached to the error
78
+ # @!attribute [r] metadata
79
+ # @return [Hash] The trailing metadata that was attached to the error
76
80
  attr_reader :metadata
77
81
 
78
82
  ##
@@ -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
  ##
@@ -16,20 +16,6 @@
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
18
  module Gruf
19
- ##
20
- # Handles internal gruf logging requests
21
- #
22
- module Logger
23
- ##
24
- # Return the current Gruf logger
25
- #
26
- # @return [Logger]
27
- #
28
- def logger
29
- Gruf.logger
30
- end
31
- end
32
-
33
19
  ##
34
20
  # Handles grpc internal logging requests
35
21
  #
@@ -1,9 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
3
18
  module Gruf
4
19
  module Integrations
5
20
  module Rails
21
+ ##
22
+ # Rails integration for Gruf, that currently only manages code autoloading in a Rails context
23
+ #
6
24
  class Railtie < ::Rails::Railtie
25
+ initializer 'gruf.initializer' do |app|
26
+ config.before_configuration do
27
+ # Remove autoloading of the controllers path from Rails' zeitwerk, so that we ensure Gruf's zeitwerk
28
+ # properly manages them itself. This allows us to manage code reloading and logging in Gruf specifically
29
+ app.config.eager_load_paths -= [::Gruf.controllers_path] if app.config.respond_to?(:eager_load_paths)
30
+ if ::Rails.respond_to?(:autoloaders) # if we're on a late enough version of rails
31
+ ::Rails.autoloaders.each do |autoloader|
32
+ autoloader.ignore(Gruf.controllers_path)
33
+ end
34
+ end
35
+ end
36
+ end
7
37
  end
8
38
  end
9
39
  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
  ##
@@ -41,13 +44,3 @@ module Gruf
41
44
  end
42
45
  end
43
46
  end
44
-
45
- require_relative 'client_interceptor'
46
- require_relative 'server_interceptor'
47
- require_relative 'context'
48
- require_relative 'timer'
49
- require_relative 'active_record/connection_reset'
50
- require_relative 'authentication/basic'
51
- require_relative 'instrumentation/statsd'
52
- require_relative 'instrumentation/output_metadata_timer'
53
- require_relative 'instrumentation/request_logging/interceptor'
@@ -38,7 +38,7 @@ module Gruf
38
38
  def intercept!(&block)
39
39
  return yield if @interceptors.none?
40
40
 
41
- i = @interceptors.pop
41
+ i = @interceptors.shift
42
42
  return yield unless i
43
43
 
44
44
  logger.debug "Intercepting request with interceptor: #{i.class}"
@@ -16,9 +16,6 @@
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
18
  require 'socket'
19
- require_relative 'formatters/base'
20
- require_relative 'formatters/logstash'
21
- require_relative 'formatters/plain'
22
19
 
23
20
  module Gruf
24
21
  module Interceptors
@@ -28,8 +28,12 @@ module Gruf
28
28
  # @property [Float] elapsed The elapsed time of the request
29
29
  #
30
30
  class Result
31
- attr_reader :message,
32
- :elapsed
31
+ # @!attribute [r] message
32
+ # @return [Object] The returned protobuf message
33
+ attr_reader :message
34
+ # @return [r] elapsed
35
+ # @return [Float] The time elapsed for this interceptor to execute
36
+ attr_reader :elapsed
33
37
 
34
38
  ##
35
39
  # @param [Object] message The protobuf message
@@ -53,7 +57,7 @@ module Gruf
53
57
  # @return [String] The name of the message class
54
58
  #
55
59
  def message_class_name
56
- @message.class.name
60
+ @message.class.name.to_s
57
61
  end
58
62
 
59
63
  ##
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ module Gruf
19
+ ##
20
+ # Handles internal gruf logging requests
21
+ #
22
+ module Logger
23
+ ##
24
+ # Return the current Gruf logger
25
+ #
26
+ # @return [Logger]
27
+ #
28
+ def logger
29
+ Gruf.logger
30
+ end
31
+ end
32
+ end
@@ -21,15 +21,20 @@ module Gruf
21
21
  # Encapsulates the context of an outbound client request
22
22
  #
23
23
  class RequestContext
24
- # @var [Symbol]
24
+ # @!attribute [r] type
25
+ # @return [Symbol]
25
26
  attr_reader :type
26
- # @var [Enumerable] requests
27
+ # @!attribute [r] requests
28
+ # @return [Enumerable] requests
27
29
  attr_reader :requests
28
- # @var [GRPC::ActiveCall]
30
+ # @!attribute [r] call
31
+ # @return [GRPC::ActiveCall]
29
32
  attr_reader :call
30
- # @var [Method] method
33
+ # @!attribute [r] method
34
+ # @return [Method] method
31
35
  attr_reader :method
32
- # @var [Hash] metadata
36
+ # @!attribute [r] metadata
37
+ # @return [Hash] metadata
33
38
  attr_reader :metadata
34
39
 
35
40
  ##
@@ -55,7 +60,7 @@ module Gruf
55
60
  # @return [String]
56
61
  #
57
62
  def method_name
58
- @method.to_s.split('/').last
63
+ @method.to_s.split('/').last.to_s
59
64
  end
60
65
 
61
66
  ##
@@ -64,7 +69,7 @@ module Gruf
64
69
  # @return [String]
65
70
  #
66
71
  def route_key
67
- @method[1..-1].underscore.tr('/', '.')
72
+ @method[1..].to_s.underscore.tr('/', '.')
68
73
  end
69
74
  end
70
75
  end
data/lib/gruf/response.rb CHANGED
@@ -20,17 +20,23 @@ module Gruf
20
20
  # Wraps the active call operation to provide metadata and timing around the request
21
21
  #
22
22
  class Response
23
- # @return [GRPC::ActiveCall::Operation] The operation that was executed for the given request
23
+ # @!attribute [r] operation
24
+ # @return [GRPC::ActiveCall::Operation] The operation that was executed for the given request
24
25
  attr_reader :operation
25
- # @return [Hash] The metadata that was attached to the operation
26
+ # @!attribute [r] metadata
27
+ # @return [Hash] The metadata that was attached to the operation
26
28
  attr_reader :metadata
27
- # @return [Hash] The trailing metadata that the service returned
29
+ # @!attribute [r] trailing_metadata
30
+ # @return [Hash] The trailing metadata that the service returned
28
31
  attr_reader :trailing_metadata
29
- # @return [Time] The set deadline on the call
32
+ # @!attribute [r] deadline
33
+ # @return [Time] The set deadline on the call
30
34
  attr_reader :deadline
31
- # @return [Boolean] Whether or not the operation was cancelled
35
+ # @!attribute [r] cancelled
36
+ # @return [Boolean] Whether or not the operation was cancelled
32
37
  attr_reader :cancelled
33
- # @return [Float] The time that the request took to execute
38
+ # @!attribute [r] execution_time
39
+ # @return [Float] The time that the request took to execute
34
40
  attr_reader :execution_time
35
41
 
36
42
  ##
@@ -22,7 +22,8 @@ module Gruf
22
22
  # Base class for serialization of errors for transport across the grpc protocol
23
23
  #
24
24
  class Base
25
- # @return [Gruf::Error|String] The error being serialized
25
+ # @!attribute [r] error
26
+ # @return [Gruf::Error|String] The error being serialized
26
27
  attr_reader :error
27
28
 
28
29
  ##