istox_gruf 2.7.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 +7 -0
- data/CHANGELOG.md +246 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/README.md +544 -0
- data/bin/gruf +29 -0
- data/lib/gruf.rb +50 -0
- data/lib/gruf/cli/executor.rb +99 -0
- data/lib/gruf/client.rb +217 -0
- data/lib/gruf/client/error.rb +66 -0
- data/lib/gruf/client/error_factory.rb +105 -0
- data/lib/gruf/configuration.rb +137 -0
- data/lib/gruf/controllers/base.rb +102 -0
- data/lib/gruf/controllers/request.rb +121 -0
- data/lib/gruf/controllers/service_binder.rb +117 -0
- data/lib/gruf/error.rb +230 -0
- data/lib/gruf/errors/debug_info.rb +56 -0
- data/lib/gruf/errors/field.rb +56 -0
- data/lib/gruf/errors/helpers.rb +44 -0
- data/lib/gruf/hooks/base.rb +34 -0
- data/lib/gruf/hooks/executor.rb +47 -0
- data/lib/gruf/hooks/registry.rb +159 -0
- data/lib/gruf/instrumentable_grpc_server.rb +64 -0
- data/lib/gruf/integrations/rails/railtie.rb +10 -0
- data/lib/gruf/interceptors/active_record/connection_reset.rb +48 -0
- data/lib/gruf/interceptors/authentication/basic.rb +87 -0
- data/lib/gruf/interceptors/base.rb +53 -0
- data/lib/gruf/interceptors/client_interceptor.rb +125 -0
- data/lib/gruf/interceptors/context.rb +56 -0
- data/lib/gruf/interceptors/instrumentation/output_metadata_timer.rb +61 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/formatters/base.rb +41 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/formatters/logstash.rb +43 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/formatters/plain.rb +48 -0
- data/lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb +225 -0
- data/lib/gruf/interceptors/instrumentation/statsd.rb +82 -0
- data/lib/gruf/interceptors/registry.rb +161 -0
- data/lib/gruf/interceptors/server_interceptor.rb +34 -0
- data/lib/gruf/interceptors/timer.rb +85 -0
- data/lib/gruf/loggable.rb +30 -0
- data/lib/gruf/logging.rb +53 -0
- data/lib/gruf/outbound/request_context.rb +71 -0
- data/lib/gruf/response.rb +71 -0
- data/lib/gruf/serializers/errors/base.rb +57 -0
- data/lib/gruf/serializers/errors/json.rb +43 -0
- data/lib/gruf/server.rb +294 -0
- data/lib/gruf/synchronized_client.rb +97 -0
- data/lib/gruf/timer.rb +78 -0
- data/lib/gruf/version.rb +20 -0
- metadata +203 -0
@@ -0,0 +1,97 @@
|
|
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
|
+
require 'concurrent'
|
19
|
+
|
20
|
+
module Gruf
|
21
|
+
##
|
22
|
+
# Ensures that we only have one active call to a given endpoint with a given set of params. This can be useful
|
23
|
+
# to mitigate thundering herds.
|
24
|
+
#
|
25
|
+
class SynchronizedClient < Gruf::Client
|
26
|
+
attr_reader :unsynchronized_methods
|
27
|
+
|
28
|
+
##
|
29
|
+
# Initialize the client and setup the stub
|
30
|
+
#
|
31
|
+
# @param [Module] service The namespace of the client Stub that is desired to load
|
32
|
+
# @param [Hash] options A hash of options for the client
|
33
|
+
# @option options [Array] :unsynchronized_methods A list of methods (as symbols) that
|
34
|
+
# should be excluded from synchronization
|
35
|
+
# @option options [Integer] :internal_cache_expiry The length of time to keep results
|
36
|
+
# around for other threads to fetch (in seconds)
|
37
|
+
# @param [Hash] client_options A hash of options to pass to the gRPC client stub
|
38
|
+
#
|
39
|
+
def initialize(service:, options: {}, client_options: {})
|
40
|
+
@unsynchronized_methods = options.delete(:unsynchronized_methods) { [] }
|
41
|
+
@expiry = options.delete(:internal_cache_expiry) { Gruf.synchronized_client_internal_cache_expiry }
|
42
|
+
@locks = Concurrent::Map.new
|
43
|
+
@results = Concurrent::Map.new
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Call the client's method with given params. If another call is already active for the same endpoint and the same
|
49
|
+
# params, block until the active call is complete. When unblocked, callers will get a copy of the original result.
|
50
|
+
#
|
51
|
+
# @param [String|Symbol] request_method The method that is being requested on the service
|
52
|
+
# @param [Hash] params (Optional) A hash of parameters that will be inserted into the gRPC request
|
53
|
+
# message that is required for the given above call
|
54
|
+
# @param [Hash] metadata (Optional) A hash of metadata key/values that are transported with the client request
|
55
|
+
# @param [Hash] opts (Optional) A hash of options to send to the gRPC request_response method
|
56
|
+
# @return [Gruf::Response] The response from the server
|
57
|
+
# @raise [Gruf::Client::Error|GRPC::BadStatus] If an error occurs, an exception will be raised according to the
|
58
|
+
# error type that was returned
|
59
|
+
#
|
60
|
+
def call(request_method, params = {}, metadata = {}, opts = {}, &block)
|
61
|
+
# Allow for bypassing extra behavior for selected methods
|
62
|
+
return super if unsynchronized_methods.include?(request_method.to_sym)
|
63
|
+
|
64
|
+
# Generate a unique key based on the method and params
|
65
|
+
key = "#{request_method}.#{params.hash}"
|
66
|
+
|
67
|
+
# Create a lock for this call if we haven't seen it already, then acquire it
|
68
|
+
lock = @locks.compute_if_absent(key) { Mutex.new }
|
69
|
+
lock.synchronize do
|
70
|
+
# Return value from results cache if it exists. This occurs for callers that were
|
71
|
+
# waiting on the lock while the first caller was making the actual grpc call.
|
72
|
+
response = @results.get(lock)
|
73
|
+
if response
|
74
|
+
Gruf.logger.debug "Returning cached result for #{key}:#{lock.inspect}"
|
75
|
+
next response
|
76
|
+
end
|
77
|
+
|
78
|
+
# Make the grpc call and record response for other callers that are blocked
|
79
|
+
# on the same lock
|
80
|
+
response = super
|
81
|
+
@results.put(lock, response)
|
82
|
+
|
83
|
+
# Schedule a task to come in later and clean out result to prevent memory bloat
|
84
|
+
Concurrent::ScheduledTask.new(@expiry, args: [@results, lock]) { |h, k| h.delete(k) }.execute
|
85
|
+
|
86
|
+
# Remove the lock from the map. The next caller to come through with the
|
87
|
+
# same params will create a new lock and start the process over again.
|
88
|
+
# Anyone who was waiting on this call will be using a local reference
|
89
|
+
# to the same lock as us, and will fetch the result from the cache.
|
90
|
+
@locks.delete(key)
|
91
|
+
|
92
|
+
# Return response
|
93
|
+
response
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/gruf/timer.rb
ADDED
@@ -0,0 +1,78 @@
|
|
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
|
+
# Times a given block and returns the result and the elapsed time as a Float
|
21
|
+
#
|
22
|
+
# result = Timer.time { do_my_thing }
|
23
|
+
#
|
24
|
+
class Timer
|
25
|
+
##
|
26
|
+
# Represents a timer result that contains both the elapsed time and the result of the block
|
27
|
+
#
|
28
|
+
# result = Timer.time { do_my_thing }
|
29
|
+
# result.time # => 1.10123
|
30
|
+
# result.result # => 'my_thing_is_done'
|
31
|
+
#
|
32
|
+
class Result
|
33
|
+
# @return [Object] result The result of the block that was called
|
34
|
+
attr_reader :result
|
35
|
+
# @return [Float] time The time, in ms, of the block execution
|
36
|
+
attr_reader :time
|
37
|
+
|
38
|
+
##
|
39
|
+
# Initialize the result object
|
40
|
+
#
|
41
|
+
# @param [Object] result The result of the block that was called
|
42
|
+
# @param [Float] time The time, in ms, of the block execution
|
43
|
+
#
|
44
|
+
def initialize(result, time)
|
45
|
+
@result = result
|
46
|
+
@time = time.to_f
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Was this result a successful result?
|
51
|
+
#
|
52
|
+
# @return [Boolean] Whether or not this result was a success
|
53
|
+
#
|
54
|
+
def success?
|
55
|
+
!result.is_a?(GRPC::BadStatus) && !result.is_a?(StandardError) && !result.is_a?(GRPC::Core::CallError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Times a given block by recording start and end times
|
61
|
+
#
|
62
|
+
# result = Timer.time { do_my_thing }
|
63
|
+
#
|
64
|
+
# @return [Timer::Result] Returns the timed result of the block
|
65
|
+
#
|
66
|
+
def self.time
|
67
|
+
start_time = Time.now
|
68
|
+
begin
|
69
|
+
result = yield
|
70
|
+
rescue GRPC::BadStatus, StandardError, GRPC::Core::CallError => e
|
71
|
+
result = e
|
72
|
+
end
|
73
|
+
end_time = Time.now
|
74
|
+
elapsed = (end_time - start_time) * 1000.0
|
75
|
+
Result.new(result, elapsed)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/gruf/version.rb
ADDED
@@ -0,0 +1,20 @@
|
|
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
|
+
VERSION = '2.7.1'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: istox_gruf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.7.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shaun McCormick
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.11'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.11'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: grpc
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: grpc-tools
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.10'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: concurrent-ruby
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: slop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '4.6'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '4.6'
|
125
|
+
description: gRPC Ruby Framework for building complex gRPC applications at scale
|
126
|
+
email:
|
127
|
+
- splittingred@gmail.com
|
128
|
+
executables:
|
129
|
+
- gruf
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- CHANGELOG.md
|
134
|
+
- CODE_OF_CONDUCT.md
|
135
|
+
- README.md
|
136
|
+
- bin/gruf
|
137
|
+
- lib/gruf.rb
|
138
|
+
- lib/gruf/cli/executor.rb
|
139
|
+
- lib/gruf/client.rb
|
140
|
+
- lib/gruf/client/error.rb
|
141
|
+
- lib/gruf/client/error_factory.rb
|
142
|
+
- lib/gruf/configuration.rb
|
143
|
+
- lib/gruf/controllers/base.rb
|
144
|
+
- lib/gruf/controllers/request.rb
|
145
|
+
- lib/gruf/controllers/service_binder.rb
|
146
|
+
- lib/gruf/error.rb
|
147
|
+
- lib/gruf/errors/debug_info.rb
|
148
|
+
- lib/gruf/errors/field.rb
|
149
|
+
- lib/gruf/errors/helpers.rb
|
150
|
+
- lib/gruf/hooks/base.rb
|
151
|
+
- lib/gruf/hooks/executor.rb
|
152
|
+
- lib/gruf/hooks/registry.rb
|
153
|
+
- lib/gruf/instrumentable_grpc_server.rb
|
154
|
+
- lib/gruf/integrations/rails/railtie.rb
|
155
|
+
- lib/gruf/interceptors/active_record/connection_reset.rb
|
156
|
+
- lib/gruf/interceptors/authentication/basic.rb
|
157
|
+
- lib/gruf/interceptors/base.rb
|
158
|
+
- lib/gruf/interceptors/client_interceptor.rb
|
159
|
+
- lib/gruf/interceptors/context.rb
|
160
|
+
- lib/gruf/interceptors/instrumentation/output_metadata_timer.rb
|
161
|
+
- lib/gruf/interceptors/instrumentation/request_logging/formatters/base.rb
|
162
|
+
- lib/gruf/interceptors/instrumentation/request_logging/formatters/logstash.rb
|
163
|
+
- lib/gruf/interceptors/instrumentation/request_logging/formatters/plain.rb
|
164
|
+
- lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb
|
165
|
+
- lib/gruf/interceptors/instrumentation/statsd.rb
|
166
|
+
- lib/gruf/interceptors/registry.rb
|
167
|
+
- lib/gruf/interceptors/server_interceptor.rb
|
168
|
+
- lib/gruf/interceptors/timer.rb
|
169
|
+
- lib/gruf/loggable.rb
|
170
|
+
- lib/gruf/logging.rb
|
171
|
+
- lib/gruf/outbound/request_context.rb
|
172
|
+
- lib/gruf/response.rb
|
173
|
+
- lib/gruf/serializers/errors/base.rb
|
174
|
+
- lib/gruf/serializers/errors/json.rb
|
175
|
+
- lib/gruf/server.rb
|
176
|
+
- lib/gruf/synchronized_client.rb
|
177
|
+
- lib/gruf/timer.rb
|
178
|
+
- lib/gruf/version.rb
|
179
|
+
homepage: https://github.com/bigcommerce/gruf
|
180
|
+
licenses:
|
181
|
+
- MIT
|
182
|
+
metadata: {}
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
require_paths:
|
186
|
+
- lib
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - "~>"
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '2.4'
|
192
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
requirements: []
|
198
|
+
rubyforge_project:
|
199
|
+
rubygems_version: 2.7.9
|
200
|
+
signing_key:
|
201
|
+
specification_version: 4
|
202
|
+
summary: gRPC Ruby Framework
|
203
|
+
test_files: []
|