gruf 2.9.1 → 2.15.1

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: bffd546b0bd27dcd8cd54146065623e73e0396211ae263985a197255bb8ec48a
4
- data.tar.gz: 9b0364643ab5c1008a330ed61c8fba4458f9b075c34eea81acb10de4ee70f53d
3
+ metadata.gz: 5186fbfc554b119075aff88683ee7f1661a884d96d9766e59664d10805bd4ab2
4
+ data.tar.gz: 68b995a644b15dc703595df4e35a25539e0edf77d5f5218bffa28253b60eedbf
5
5
  SHA512:
6
- metadata.gz: 3ef4637ca552b572f77b270ccdc491c660b62d7c1d8ff85fe67151cf22f09e92f18a9b88b63d31e956411cb46380ba695e0eccc74d47a2095c8fc7d6ebfaf838
7
- data.tar.gz: 0f38cc6c69487f1cab2ebc5e07b5a06de20f5e35d0000ad4c80a021288557aaaef2acf58fe254be6dc292ddd2e764976acfdd65578a7a0233c663dea83018eb3
6
+ metadata.gz: 8328cccfcc712c21cb5a477939762524d774d3d45a0882217fe3b7d701cfda90e9dcd27af7ab4c4cbc73ca46d420d85e55be3712efc950590212658030217c40
7
+ data.tar.gz: 2cf04dce0c4e378edf56ab6b204293ce2b4dc660d2ac103ac55d99e893891ac3a76feb2e05dee4ac3371b47083fd8523441e7e2c87881bacd2511b016a1965b3
data/CHANGELOG.md CHANGED
@@ -2,11 +2,67 @@ Changelog for the gruf gem. This includes internal history before the gem was ma
2
2
 
3
3
  ### Pending release
4
4
 
5
- ### 2.9.1
5
+ ### 2.15.1
6
+
7
+ - Fix issue where GRPC_SERVER_POOL_KEEP_ALIVE and GRPC_SERVER_POLL_PERIOD when set via ENV are not cast to int
8
+
9
+ ### 2.15.0
10
+
11
+ - NOTE: This changes the way that gruf controllers are autoloaded. See [UPGRADING.md] for more details.
12
+ - Autoload Gruf Controllers with zeitwerk, allowing for code reloading in development environments
13
+ - Add `GRUF_CONTROLLERS_PATH` ENV to allow ENV-based runtime configuration of path to gruf controller files
14
+ - Move `ServiceBinder` from instance to static class for performance improvements
15
+ - Use zeitwerk for autoloading
16
+ - Update gem metadata
17
+ - Update `Gruf:Configuration#environment` to use `ENV.fetch`
18
+
19
+ ### 2.14.1
20
+
21
+ - Fix issue where the server object hits thread contention in certain race conditions
22
+
23
+ ### 2.14.0
24
+
25
+ - Set default client host to 0.0.0.0:9001 (same as default server host)
26
+ - Add support for Ruby 3.1
27
+
28
+ ### 2.13.1
29
+
30
+ - Fix issue with race condition in server starts where servers may fail to bind connections and never reach
31
+ serving state (fixes #147)
32
+
33
+ ### 2.13.0
34
+
35
+ - Remove server mutex handling in deference to core grpc signal handling
36
+ - Relax grpc pin as upstream regression is fixed
37
+
38
+ ### 2.12.0
39
+
40
+ - Fixed interceptor order to be FIFO as documented, instead of FILO (fixes #139)
41
+
42
+ ### 2.11.0
43
+
44
+ - Restrict grpc gem to <= 1.41.0 due to regressions in grpc 1.42.x
45
+ - Fallback to stdout logger at INFO if no logger is setup
46
+ - Better handling of namespace collisions with Rails
47
+ - Add `GRPC_SERVER_HOST` and `GRPC_SERVER_PORT` for ENV configuration of the server host+port
48
+ - Add `GRPC_BACKTRACE_ON_ERROR` as available ENV configuration
49
+ - Add default ENV-based configuration of the GRPC server pool
50
+ - `GRPC_SERVER_POOL_SIZE` - sets the size of the GRPC server pool
51
+ - `GRPC_SERVER_POOL_KEEP_ALIVE` - keep alive time for threads spawned by the server pool
52
+ - `GRPC_SERVER_POLL_PERIOD` - period in seconds to poll for workers in the gRPC server pool
53
+ - Improve Yardoc support across the library
54
+ - Added attribute-based documentation for Gruf configuration options
55
+ - Add mfa required for gemspec metadata
56
+
57
+ ### 2.10.0
6
58
 
7
59
  - Drop support for Ruby 2.4/2.5 to align with Ruby EOL schedule, supporting 2.6+ only
8
60
  - Allow for float/TimeSpec timeout values on clients
9
61
 
62
+ ### 2.9.1
63
+
64
+ - Allow for float/TimeSpec timeout values on clients (backport from 2.10.0)
65
+
10
66
  ### 2.9.0
11
67
 
12
68
  - Change to racially neutral terminology across library
@@ -25,7 +81,7 @@ Changelog for the gruf gem. This includes internal history before the gem was ma
25
81
 
26
82
  ### 2.8.0
27
83
 
28
- - Pass the controller request object into the request logging formatters [#92]
84
+ - Pass the controller request object into the request logging formatters [#92]
29
85
 
30
86
  ### 2.7.1
31
87
 
@@ -38,12 +94,12 @@ Changelog for the gruf gem. This includes internal history before the gem was ma
38
94
  ### 2.6.1
39
95
 
40
96
  - Add frozen_string_literal: true to files, update rubocop to 0.68
41
-
97
+
42
98
  ### 2.6.0
43
99
 
44
100
  - Drop Ruby 2.2 support
45
- - Abstract gruf controller's send to make it usable in filters
46
- - Adjusts configuration reset into a Railtie for Rails systems to ensure proper OOE
101
+ - Abstract gruf controller's send to make it usable in filters
102
+ - Adjusts configuration reset into a Railtie for Rails systems to ensure proper OOE
47
103
  - Bump rubocop to 0.64, address violations, update activesupport/concurrent-ruby dependencies to have a min version
48
104
 
49
105
  ### 2.5.2
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # gruf - gRPC Ruby Framework
2
2
 
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)
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) [![Maintainability](https://api.codeclimate.com/v1/badges/4a8e9269f99100aeb7cb/maintainability)](https://codeclimate.com/github/bigcommerce/gruf/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/4a8e9269f99100aeb7cb/test_coverage)](https://codeclimate.com/github/bigcommerce/gruf/test_coverage)
4
4
 
5
- gruf is a Ruby framework that wraps the [gRPC Ruby library](https://github.com/grpc/grpc/tree/main/src/ruby) to
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.
7
7
 
8
8
  It provides an abstracted server and client for gRPC services, along with other tools to help get gRPC services in Ruby
@@ -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.7.
20
+ gruf currently has active support for gRPC 1.10.x+. gruf is compatible and tested with Ruby 2.6-3.1.
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,8 +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
- $LOAD_PATH.push File.expand_path('lib', __dir__)
19
- require 'gruf/version'
18
+ require_relative 'lib/gruf/version'
20
19
 
21
20
  Gem::Specification.new do |spec|
22
21
  spec.name = 'gruf'
@@ -33,9 +32,17 @@ Gem::Specification.new do |spec|
33
32
  spec.executables << 'gruf'
34
33
  spec.require_paths = ['lib']
35
34
 
36
- spec.required_ruby_version = '>= 2.4', '< 3.1'
35
+ spec.required_ruby_version = '>= 2.6', '< 3.2'
36
+
37
+ spec.metadata = {
38
+ 'bug_tracker_uri' => 'https://github.com/bigcommerce/gruf/issues',
39
+ 'changelog_uri' => 'https://github.com/bigcommerce/gruf/CHANGELOG.md',
40
+ 'homepage_uri' => 'https://github.com/bigcommerce/gruf',
41
+ 'rubygems_mfa_required' => 'true',
42
+ 'source_code_uri' => 'https://github.com/bigcommerce/gruf',
43
+ 'wiki_uri' => 'https://github.com/bigcommerce/gruf/wiki'
44
+ }
37
45
 
38
- spec.add_development_dependency 'bundler', '~> 1.11'
39
46
  spec.add_development_dependency 'bundler-audit', '>= 0.6'
40
47
  # rubocop:disable Gemspec/RubyVersionGlobalsUsage
41
48
  spec.add_development_dependency(
@@ -57,10 +64,11 @@ Gem::Specification.new do |spec|
57
64
 
58
65
  spec.add_runtime_dependency 'activesupport', '> 4'
59
66
  spec.add_runtime_dependency 'concurrent-ruby', '> 1'
60
- spec.add_runtime_dependency 'e2mmap', '~> 0.1'
67
+ spec.add_runtime_dependency 'e2mmap', '>= 0.1'
61
68
  spec.add_runtime_dependency 'grpc', '~> 1.10'
62
69
  spec.add_runtime_dependency 'grpc-tools', '~> 1.10'
63
70
  spec.add_runtime_dependency 'json', '>= 2.3'
64
- spec.add_runtime_dependency 'slop', '~> 4.6'
65
- spec.add_runtime_dependency 'thwait', '~> 0.1'
71
+ spec.add_runtime_dependency 'slop', '>= 4.6'
72
+ spec.add_runtime_dependency 'thwait', '>= 0.1'
73
+ spec.add_runtime_dependency 'zeitwerk', '>= 2'
66
74
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2022-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
+ # Module for accessing Gruf zeitwerk-based autoloaders
21
+ #
22
+ module Autoloaders
23
+ class << self
24
+ include Enumerable
25
+
26
+ ##
27
+ # Initialize the autoloaders with a given controllers path
28
+ #
29
+ # @param [String] controllers_path The path to Gruf Controllers
30
+ #
31
+ def load!(controllers_path:)
32
+ controllers(controllers_path: controllers_path)
33
+ end
34
+
35
+ ##
36
+ # Enumerate across the managed set of autoloaders
37
+ #
38
+ def each
39
+ yield controllers
40
+ end
41
+
42
+ ##
43
+ # Reload all files managed by the autoloader
44
+ #
45
+ def reload
46
+ each(&:reload)
47
+ end
48
+
49
+ ##
50
+ # Lazily instantiate and memoize the Gruf Controllers autoloader in a thread-safe manner
51
+ #
52
+ # @return [::Gruf::Controllers::Autoloader]
53
+ #
54
+ # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
55
+ def controllers(controllers_path: nil)
56
+ controllers_mutex do
57
+ @controllers ||= ::Gruf::Controllers::Autoloader.new(path: controllers_path || ::Gruf.controllers_path)
58
+ end
59
+ end
60
+ # rubocop:enable ThreadSafety/InstanceVariableInClassMethod
61
+
62
+ ##
63
+ # Handle mutations to the controllers autoloader in a thread-safe manner
64
+ #
65
+ # rubocop:disable ThreadSafety/InstanceVariableInClassMethod
66
+ def controllers_mutex(&block)
67
+ @controllers_mutex ||= begin
68
+ require 'monitor'
69
+ Monitor.new
70
+ end
71
+ @controllers_mutex.synchronize(&block)
72
+ end
73
+ # rubocop:enable ThreadSafety/InstanceVariableInClassMethod
74
+ end
75
+ end
76
+ end
@@ -23,8 +23,14 @@ module Gruf
23
23
  # Handles execution of the gruf binstub, along with command-line arguments
24
24
  #
25
25
  class Executor
26
+ class NoServicesBoundError < StandardError; end
27
+
26
28
  ##
27
29
  # @param [Hash|ARGV]
30
+ # @param [::Gruf::Server|NilClass] server
31
+ # @param [Array<Class>|NilClass] services
32
+ # @param [Gruf::Hooks::Executor|NilClass] hook_executor
33
+ # @param [Logger|NilClass] logger
28
34
  #
29
35
  def initialize(
30
36
  args = ARGV,
@@ -35,7 +41,7 @@ module Gruf
35
41
  )
36
42
  @args = args
37
43
  setup! # ensure we set some defaults from CLI here so we can allow configuration
38
- @services = services || Gruf.services
44
+ @services = services.is_a?(Array) ? services : []
39
45
  @hook_executor = hook_executor || Gruf::Hooks::Executor.new(hooks: Gruf.hooks&.prepare)
40
46
  @server = server || Gruf::Server.new(Gruf.server_options)
41
47
  @logger = logger || Gruf.logger || ::Logger.new($stderr)
@@ -46,6 +52,17 @@ module Gruf
46
52
  #
47
53
  def run
48
54
  exception = nil
55
+ # wait to load controllers until last possible second to allow late configuration
56
+ ::Gruf.autoloaders.load!(controllers_path: Gruf.controllers_path)
57
+ # allow lazy registering globally as late as possible, this allows more flexible binstub injections
58
+ @services = ::Gruf.services unless @services&.any?
59
+
60
+ unless @services.any?
61
+ raise NoServicesBoundError,
62
+ 'No services bound to this gruf process; please bind a service to a Gruf controller ' \
63
+ 'to start the server successfully'
64
+ end
65
+
49
66
  begin
50
67
  @services.each { |s| @server.add_service(s) }
51
68
  @hook_executor.call(:before_server_start, server: @server)
@@ -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
  ##
@@ -36,33 +37,5 @@ module Gruf
36
37
  super
37
38
  end
38
39
  end
39
-
40
- ##
41
- # See https://github.com/grpc/grpc-go/blob/master/codes/codes.go for a detailed summary of each error type
42
- #
43
- module Errors
44
- class Base < Gruf::Client::Error; end
45
- class Error < Base; end
46
- class Validation < Base; end
47
-
48
- class Ok < Base; end
49
-
50
- class InvalidArgument < Validation; end
51
- class NotFound < Validation; end
52
- class AlreadyExists < Validation; end
53
- class OutOfRange < Validation; end
54
-
55
- class Cancelled < Error; end
56
- class DataLoss < Error; end
57
- class DeadlineExceeded < Error; end
58
- class FailedPrecondition < Error; end
59
- class Internal < Error; end
60
- class PermissionDenied < Error; end
61
- class ResourceExhausted < Error; end
62
- class Unauthenticated < Error; end
63
- class Unavailable < Error; end
64
- class Unimplemented < Error; end
65
- class Unknown < Error; end
66
- end
67
40
  end
68
41
  end
@@ -0,0 +1,48 @@
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
+ class Client < SimpleDelegator
20
+ ##
21
+ # See https://github.com/grpc/grpc-go/blob/master/codes/codes.go for a detailed summary of each error type
22
+ #
23
+ module Errors
24
+ class Base < Gruf::Client::Error; end
25
+ class Error < Base; end
26
+ class Validation < Base; end
27
+
28
+ class Ok < Base; end
29
+
30
+ class InvalidArgument < Validation; end
31
+ class NotFound < Validation; end
32
+ class AlreadyExists < Validation; end
33
+ class OutOfRange < Validation; end
34
+
35
+ class Cancelled < Error; end
36
+ class DataLoss < Error; end
37
+ class DeadlineExceeded < Error; end
38
+ class FailedPrecondition < Error; end
39
+ class Internal < Error; end
40
+ class PermissionDenied < Error; end
41
+ class ResourceExhausted < Error; end
42
+ class Unauthenticated < Error; end
43
+ class Unavailable < Error; end
44
+ class Unimplemented < Error; end
45
+ class Unknown < Error; end
46
+ end
47
+ end
48
+ end
data/lib/gruf/client.rb CHANGED
@@ -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 'client/error'
19
- require_relative 'client/error_factory'
20
-
21
18
  module Gruf
22
19
  ##
23
20
  # Abstracts out the calling interface for interacting with gRPC clients. Streamlines calling and provides
@@ -38,11 +35,14 @@ module Gruf
38
35
  class Client < SimpleDelegator
39
36
  include Gruf::Loggable
40
37
 
41
- # @return [Class] The base, friendly name of the service being requested
38
+ # @!attribute [r] base_klass
39
+ # @return [Class] The base, friendly name of the service being requested
42
40
  attr_reader :base_klass
43
- # @return [Class] The class name of the gRPC service being requested
41
+ # @!attribute [r] service_klass
42
+ # @return [Class] The class name of the gRPC service being requested
44
43
  attr_reader :service_klass
45
- # @return [Hash] A hash of options for the client
44
+ # @!attribute [r] opts
45
+ # @return [Hash] A hash of options for the client
46
46
  attr_reader :opts
47
47
 
48
48
  ##
@@ -230,7 +230,7 @@ module Gruf
230
230
  GRPC::Core::TimeConsts::ZERO
231
231
  elsif timeout.is_a?(GRPC::Core::TimeSpec)
232
232
  timeout
233
- elsif timeout.is_a?(Numeric)
233
+ elsif timeout.is_a?(Numeric) # rubocop:disable Lint/DuplicateBranch
234
234
  timeout
235
235
  elsif timeout.respond_to?(:to_f)
236
236
  timeout.to_f
@@ -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',
@@ -27,7 +84,7 @@ module Gruf
27
84
  interceptors: nil,
28
85
  hooks: nil,
29
86
  default_channel_credentials: nil,
30
- default_client_host: '',
87
+ default_client_host: '0.0.0.0:9001',
31
88
  use_ssl: false,
32
89
  ssl_crt_file: '',
33
90
  ssl_key_file: '',
@@ -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
@@ -100,26 +157,40 @@ module Gruf
100
157
  VALID_CONFIG_KEYS.each do |k, v|
101
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
- self.controllers_path = root_path.to_s.empty? ? 'app/rpc' : "#{root_path}/app/rpc"
168
+ cp = ::ENV.fetch('GRUF_CONTROLLERS_PATH', 'app/rpc').to_s
169
+ self.controllers_path = root_path.to_s.empty? ? cp : "#{root_path}/#{cp}"
170
+ self.backtrace_on_error = ::ENV.fetch('GRPC_BACKTRACE_ON_ERROR', 0).to_i.positive?
171
+ self.rpc_server_options = {
172
+ max_waiting_requests: ::ENV.fetch('GRPC_SERVER_MAX_WAITING_REQUESTS',
173
+ GRPC::RpcServer::DEFAULT_MAX_WAITING_REQUESTS).to_i,
174
+ pool_size: ::ENV.fetch('GRPC_SERVER_POOL_SIZE', GRPC::RpcServer::DEFAULT_POOL_SIZE).to_i,
175
+ pool_keep_alive: ::ENV.fetch('GRPC_SERVER_POOL_KEEP_ALIVE', GRPC::Pool::DEFAULT_KEEP_ALIVE).to_i,
176
+ poll_period: ::ENV.fetch('GRPC_SERVER_POLL_PERIOD', GRPC::RpcServer::DEFAULT_POLL_PERIOD).to_i,
177
+ connect_md_proc: nil,
178
+ server_args: {}
179
+ }
116
180
  if use_default_interceptors
117
- interceptors.use(Gruf::Interceptors::ActiveRecord::ConnectionReset)
118
- interceptors.use(Gruf::Interceptors::Instrumentation::OutputMetadataTimer)
181
+ interceptors.use(::Gruf::Interceptors::ActiveRecord::ConnectionReset)
182
+ interceptors.use(::Gruf::Interceptors::Instrumentation::OutputMetadataTimer)
119
183
  end
120
184
  options
121
185
  end
122
186
 
187
+ ##
188
+ # @return [Boolean]
189
+ #
190
+ def development?
191
+ environment == 'development'
192
+ end
193
+
123
194
  private
124
195
 
125
196
  ##
@@ -128,11 +199,30 @@ module Gruf
128
199
  # @return [String] The current Ruby environment
129
200
  #
130
201
  def environment
131
- if defined?(Rails)
132
- Rails.env.to_s
202
+ if defined?(::Rails)
203
+ ::Rails.env.to_s
204
+ else
205
+ ENV.fetch('RACK_ENV') { ENV.fetch('RAILS_ENV', 'development') }.to_s
206
+ end
207
+ end
208
+
209
+ ##
210
+ # Dynamically determine the appropriate logger
211
+ #
212
+ def determine_loggers
213
+ if defined?(::Rails) && ::Rails.logger
214
+ self.logger = ::Rails.logger
133
215
  else
134
- (ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development').to_s
216
+ require 'logger'
217
+ self.logger = ::Logger.new($stdout)
218
+ log_level = ::ENV.fetch('LOG_LEVEL', 'info').to_s.upcase
219
+ begin
220
+ logger.level = ::Logger::Severity.const_get(log_level)
221
+ rescue NameError => _e
222
+ logger.level = ::Logger::Severity::INFO
223
+ end
135
224
  end
225
+ self.grpc_logger = logger if grpc_logger.nil?
136
226
  end
137
227
  end
138
228
  end
@@ -0,0 +1,74 @@
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
+ module Controllers
20
+ ##
21
+ # Handles autoloading of Gruf controllers in the application path. This allows for code reloading on Gruf
22
+ # controllers.
23
+ #
24
+ class Autoloader
25
+ include ::Gruf::Loggable
26
+
27
+ # @!attribute [r] path
28
+ # @return [String] The path for this autoloader
29
+ attr_reader :path
30
+
31
+ ##
32
+ # @param [String] path
33
+ # @param [Boolean] reloading
34
+ # @param [String] tag
35
+ #
36
+ def initialize(path:, reloading: nil, tag: nil)
37
+ super()
38
+ @path = path
39
+ @loader = ::Zeitwerk::Loader.new
40
+ @loader.tag = tag || 'gruf-controllers'
41
+ @setup = false
42
+ @reloading_enabled = reloading || ::Gruf.development?
43
+ setup!
44
+ end
45
+
46
+ ##
47
+ # Reload all files managed by the autoloader, if reloading is enabled
48
+ #
49
+ def reload
50
+ @loader.reload if @reloading_enabled
51
+ end
52
+
53
+ private
54
+
55
+ ##
56
+ # @return [Boolean]
57
+ #
58
+ def setup!
59
+ return true if @setup
60
+
61
+ return false unless File.directory?(@path)
62
+
63
+ @loader.enable_reloading if @reloading_enabled
64
+ @loader.ignore("#{@path}/**/*_pb.rb")
65
+ @loader.push_dir(@path)
66
+ @loader.setup
67
+ # always eager load RPC files, so that the service binder can bind the Gruf::Controller instantiation
68
+ # to the gRPC Service classes
69
+ @loader.eager_load
70
+ @setup = true
71
+ end
72
+ end
73
+ end
74
+ end