gruf 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8db09af385df9c2a441b0bf6ece236e8d3a0735a
4
+ data.tar.gz: dff8c04b4439335743edb8c6cbd7e74d7cb64f43
5
+ SHA512:
6
+ metadata.gz: 040cfcf2678a142635796b35706dc1599e4b0364a4cc6a90fbc9628e02d3b273427452b3325d6e08988b53e80d2a08482879072c90927de16f697ad7f7937c3f
7
+ data.tar.gz: 3a67f98f29b8be1b9216a0c609e040308721afe822719d591cd74a82cb3d3c791b796d96eee750e096b2de7c837607377e01101b760d1fd4fb82dcc2e98ca904
@@ -0,0 +1,81 @@
1
+ Changelog for the gruf gem. This includes internal history before the gem was made.
2
+
3
+ h3. 1.0.0
4
+
5
+ - Bump gRPC to 1.4
6
+
7
+ h3. 0.14.2
8
+
9
+ - Added rubocop style-guide checks
10
+
11
+ h3. 0.14.1
12
+
13
+ - Updated license to MIT
14
+
15
+ h3. 0.14.0
16
+
17
+ - Send gRPC status 16 (Unauthenticated) instead of 7 (PermissionDenied) when authentication fails
18
+
19
+ h3. 0.13.0
20
+
21
+ - Move to gRPC 1.3.4
22
+
23
+ h4. 0.12.2
24
+
25
+ - Add outer_around hook for wrapping the entire call chain
26
+
27
+ h4. 0.12.1
28
+
29
+ - Add ability to specify a separate gRPC logger from the Gruf logger
30
+
31
+ h3. 0.12.0
32
+
33
+ - Add ability to run multiple around hooks
34
+ - Fix bug with error handling that caused error messages to repeat across streams
35
+
36
+ h3. 0.11.5
37
+
38
+ - Fix issue with around hook
39
+
40
+ h3. 0.11.4
41
+
42
+ - Add catchall rescue handler to capture uncaught exceptions and
43
+ raise a GRPC::Internal error.
44
+ - Add Gruf.backtrace_on_error configuration value. If set, Gruf
45
+ will call Service.set_debug_info with the exception backtrace
46
+ if an uncaught exception occurs.
47
+
48
+ h3. 0.11.3
49
+
50
+ - Pass the service instance into hooks for reference
51
+
52
+ h3. 0.11.2
53
+
54
+ - Ensure timer is measuring in milliseconds
55
+
56
+ h3. 0.11.1
57
+
58
+ - Fix issue with interceptor and call signature
59
+
60
+ h3. 0.11.0
61
+
62
+ - Add instrumentation layer and ability to register new instrumentors
63
+ - Add out-of-the-box statsd instrumentation support
64
+
65
+ h3. 0.10.0
66
+
67
+ - Rename Gruf::Endpoint to Gruf::Service
68
+ - Make services auto-mount to server upon declaration
69
+
70
+ h3. 0.9.2
71
+
72
+ - Support mount command on services to allow automatic setup on the server
73
+ - Cleanup and consolidate binstub to prevent need for custom binstub per-app
74
+
75
+ h3. 0.9.1
76
+
77
+ - Relax licensing to a clean BSD license
78
+
79
+ h3. 0.9.0
80
+
81
+ - Initial public release
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at splittingred@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
@@ -0,0 +1,312 @@
1
+ # gruf - gRPC Ruby Framework
2
+
3
+ [![Build Status](https://travis-ci.com/bigcommerce/gruf.svg?token=D3Cc4LCF9BgpUx4dpPpv&branch=master)](https://travis-ci.com/bigcommerce/gruf)
4
+
5
+ gruf is a Ruby framework that wraps the [gRPC Ruby library](https://github.com/grpc/grpc/tree/master/src/ruby) to
6
+ provide a more streamlined integration into Ruby and Ruby on Rails applications.
7
+
8
+ It provides an abstracted server and client for gRPC services, along with other tools to help get gRPC services in Ruby
9
+ up fast and efficiently at scale. Some of its features include:
10
+
11
+ * Abstracted server endpoints with before, around, outer around, and after hooks during an endpoint call
12
+ * Robust client error handling and metadata transport abilities
13
+ * Server authentication strategy support, with basic auth with multiple key support built in
14
+ * TLS support for client-server auth, though we recommend using [linkerd](https://linkerd.io/) instead
15
+ * Error data serialization in output metadata to allow fine-grained error handling in the transport while still
16
+ preserving gRPC BadStatus codes
17
+ * Server and client execution timings in responses
18
+
19
+ gruf currently has active support for gRPC 1.4.x. gruf is compatible and tested with with Ruby 2.2, 2.3, and 2.4. gruf
20
+ is also not [Rails](https://github.com/rails/rails)-specific, and can be used in any Ruby framework (such as
21
+ [Grape](https://github.com/ruby-grape/grape), for instance).
22
+
23
+ ## Installation
24
+
25
+ ```ruby
26
+ gem 'gruf'
27
+ ```
28
+
29
+ Then in an initializer or before use:
30
+
31
+ ```ruby
32
+ require 'gruf'
33
+ ```
34
+
35
+ ### Client
36
+
37
+ From there, you can instantiate a client given a stub service (say on an SslCertificates proto with a GetSslCertificate call):
38
+
39
+ ```ruby
40
+ require 'gruf'
41
+
42
+ id = args[:id].to_i.presence || 1
43
+
44
+ begin
45
+ client = ::Gruf::Client.new(service: MyPackage::MyService)
46
+ response = client.call(:GetMyThing, id: id)
47
+ puts response.message.inspect
48
+ rescue Gruf::Client::Error => e
49
+ puts e.error.inspect
50
+ end
51
+ ```
52
+
53
+ Note this returns a response object. The response object can provide `trailing_metadata` as well as a `execution_time`.
54
+
55
+ ### Server
56
+
57
+ Add an initializer:
58
+
59
+ ```ruby
60
+ require 'gruf'
61
+
62
+ Gruf.configure do |c|
63
+ c.server_binding_url = 'grpc.service.com:9003'
64
+ end
65
+ ```
66
+
67
+ Next, setup some handlers based on your proto configurations in `/app/rpc/`. For example, for the Thing service, with a
68
+ GetThingReq/GetThingResp call based on this proto:
69
+
70
+ ```
71
+ syntax = "proto3";
72
+
73
+ package demo;
74
+
75
+ service Thing {
76
+ rpc GetThing(GetThingReq) returns (GetSslCertificateResp) { }
77
+ }
78
+
79
+ message ThingReq {
80
+ uint64 id = 1;
81
+ }
82
+
83
+ message ThingResp {
84
+ uint64 id = 1;
85
+ string name = 2;
86
+ }
87
+ ```
88
+
89
+ You'd have this handler in `/app/rpc/demo/thing_server.rb`
90
+
91
+ ```ruby
92
+ module Demo
93
+ class ThingServer < ::Demo::ThingService::Service
94
+ include Gruf::Service
95
+
96
+ ##
97
+ # @param [Demo::GetThingReq] req
98
+ # @param [GRPC::ActiveCall] call
99
+ # @return [Demo::GetThingResp]
100
+ #
101
+ def get_thing(req, call)
102
+ ssl = Thing.find(req.id)
103
+
104
+ Demo::Things::GetThingResp.new(
105
+ id: ssl.id
106
+ )
107
+ rescue
108
+ fail!(req, call, :not_found, :thing_not_found, "Failed to find Thing with ID: #{req.id}")
109
+ end
110
+ end
111
+ end
112
+ ```
113
+
114
+ Finally, you can start the server by running:
115
+
116
+ bundle exec gruf
117
+
118
+ ### Authentication
119
+
120
+ Authentication is done via a strategy pattern and are injectable via middleware. If any of the strategies return `true`,
121
+ it will proceed the request as successful. For example, to add basic auth, you can do:
122
+
123
+ ```ruby
124
+ Gruf::Authentication::Strategies.add(:basic, Gruf::Authentication::Basic)
125
+ ```
126
+
127
+ Options to the middleware libraries can be passed through the `authentication_options` configuration option.
128
+
129
+ To add a custom authentication pattern, your class must extend the `Gruf::Authentication::Base` class, and implement
130
+ the `valid?(call)` method. For example, this class allows everyone in:
131
+
132
+ ```
133
+ class NoAuth < Gruf::Authentication::Base
134
+ def valid?(_call)
135
+ true
136
+ end
137
+ end
138
+ ```
139
+
140
+ #### Basic Auth
141
+
142
+ gruf supports simple basic authentication with an array of accepted credentials:
143
+
144
+ ```ruby
145
+ Gruf.configure do |c|
146
+ c.authentication_options = {
147
+ credentials: [{
148
+ username: 'my-username-here',
149
+ password: 'my-password-here',
150
+ },{
151
+ username: 'another-username',
152
+ password: 'another-password',
153
+ },{
154
+ password: 'a-password-only'
155
+ }]
156
+ }
157
+ end
158
+ ```
159
+
160
+ Supporting an array of credentials allow for unique credentials per service, or for easy credential rotation with
161
+ zero downtime.
162
+
163
+ ### SSL Configuration
164
+
165
+ We don't recommend using TLS for gRPC, but instead using something like [linkerd](https://linkerd.io) for TLS
166
+ encryption between services. If you need it, however, this library supports TLS.
167
+
168
+ For the client, you'll need to point to the public certificate:
169
+
170
+ ```ruby
171
+ ::Gruf::Client.new(
172
+ service: Demo::ThingService,
173
+ ssl_certificate: 'x509 public certificate here',
174
+ # OR
175
+ ssl_certificate_file: '/path/to/my.crt'
176
+ )
177
+ ```
178
+
179
+ If you want to run a server you'll need both the CRT and the key file if you want to do credentialed auth:
180
+
181
+ ```ruby
182
+ Gruf.configure do |c|
183
+ c.use_ssl = true
184
+ c.ssl_crt_file = "#{Rails.root}/config/ssl/#{Rails.env}.crt"
185
+ c.ssl_key_file = "#{Rails.root}/config/ssl/#{Rails.env}.key"
186
+ end
187
+ ```
188
+
189
+ ## Hooks
190
+
191
+ gruf supports hooks that act as interceptors around the grpc server calls, allowing you to perform actions before,
192
+ after, and even around your server endpoints. This can be used to add tracing data, connection resets in the grpc thread
193
+ pool, further instrumentation, and other things.
194
+
195
+ Adding a hook is as simple as creating a class that extends `Gruf::Hooks::Base`, and implementing it via the registry.
196
+
197
+ ### Before
198
+
199
+ A before hook passes in the method call signature, request object, and `GRPC::ActiveCall` object:
200
+ ```ruby
201
+ class MyBeforeHook < Gruf::Hooks::Base
202
+ def before(call_signature, request, active_call)
203
+ # do my thing before the call. Calling `fail!` here will prevent the call from happening.
204
+ end
205
+ end
206
+ Gruf::Hooks::Registry.add(:my_before_hook, MyBeforeHook)
207
+ ```
208
+
209
+ ### After
210
+
211
+ An after hook passes in the response object, method call signature, request object, and `GRPC::ActiveCall` object:
212
+ ```ruby
213
+ class MyAfterHook < Gruf::Hooks::Base
214
+ def after(success, response, call_signature, request, active_call)
215
+ # You can modify the response object
216
+ end
217
+ end
218
+ Gruf::Hooks::Registry.add(:my_after_hook, MyAfterHook)
219
+ ```
220
+
221
+ ### Around
222
+
223
+ An around hook passes in the method call signature, request object, `GRPC::ActiveCall` object, and the block
224
+ being executed:
225
+ ```ruby
226
+ class MyAroundHook < Gruf::Hooks::Base
227
+ def around(call_signature, request, active_call, &block)
228
+ # do my thing here
229
+ resp = yield
230
+ # do my thing there
231
+ resp
232
+ end
233
+ end
234
+ Gruf::Hooks::Registry.add(:my_around_hook, MyAroundHook)
235
+ ```
236
+
237
+ Around hooks are a special case - because each needs to wrap the call, they are run recursively within each other.
238
+ This means that if you have three hooks - `Hook1`, `Hook2`, and `Hook3` - they will run in LIFO (last in, first out)
239
+ order. `Hook3` will run, calling `Hook2`, which will then call `Hook1`, ending the chain.
240
+
241
+ ### Outer Around
242
+
243
+ And finally, an "outer" around hook passes in the method call signature, request object, `GRPC::ActiveCall`
244
+ object, and the block being executed, and executes around the _entire_ call chain (before, around, request, after):
245
+
246
+ ```ruby
247
+ class MyOuterAroundHook < Gruf::Hooks::Base
248
+ def outer_around(call_signature, request, active_call, &block)
249
+ # do my thing here
250
+ resp = yield
251
+ # do my thing there
252
+ resp
253
+ end
254
+ end
255
+ Gruf::Hooks::Registry.add(:my_outer_around_hook, MyOuterAroundHook)
256
+ ```
257
+
258
+ Outer around hooks behave similarly in execution order to around hooks.
259
+
260
+ Note: It's important to note that the authentication step happens immediately before the first _before_ hook is called,
261
+ so don't perform any actions that you want behind authentication in outer around hooks, as they are not called with
262
+ authentication.
263
+
264
+ ## Instrumentation
265
+
266
+ gruf comes out of the box with a couple of instrumentors packed in: output metadata timings, and StatsD
267
+ support.
268
+
269
+ ### Output Metadata Timing
270
+
271
+ Enabled by default, this will push timings for _successful responses_ through the response output metadata back to the
272
+ client.
273
+
274
+ ### StatsD
275
+
276
+ The StatsD support is not enabled by default. To enable it, you'll want to do:
277
+
278
+ ```ruby
279
+ Gruf.configure do |c|
280
+ c.instrumentation_options = {
281
+ statsd: {
282
+ client: ::Statsd.new('my.statsd.host', 8125),
283
+ prefix: 'my_application_prefix.rpc'
284
+ }
285
+ }
286
+ end
287
+ Gruf::Instrumentation::Registry.add(:statsd, Gruf::Instrumentation::Statsd)
288
+ ```
289
+
290
+ This will measure counts and timings for each endpoint.
291
+
292
+ ### Custom Instrumentors
293
+
294
+ Similar to hooks, simply extend the `Gruf::Instrumentation::Base` class, and implement the `call` method. See the StatsD
295
+ instrumentor for an example.
296
+
297
+ ## License
298
+
299
+ Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
300
+
301
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
302
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
303
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
304
+ persons to whom the Software is furnished to do so, subject to the following conditions:
305
+
306
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
307
+ Software.
308
+
309
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
310
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
311
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
312
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.