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.
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