tonic-rails 0.7.0-x86_64-linux-gnu → 0.8.0-x86_64-linux-gnu

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: 83bded7e4b04dc72602f73fa065ac32bde6f97631fe4450525432ef6f93df506
4
- data.tar.gz: 13bb870aa4bfb1487fa9827745aceac8c1a0a211053a9b5adafebe494975307e
3
+ metadata.gz: 53065348a46d7db7f65fe581260768aa899eb661e7bbd6ad5dfe6b87473523ed
4
+ data.tar.gz: 4b00c60ff0bafe215288329b21aa41fcc7c780c6cc589172ef8915c87ca079c8
5
5
  SHA512:
6
- metadata.gz: 539c6220bfa47fb98b506c826112ad5728bde68693c37a3479dd2727baff3b14fd07cb689c4c72419d05228a4c3042ea4ce636b44f7c1cdbad06013a2084f8ba
7
- data.tar.gz: 9ac35b6b569b9f4083ea342c5e55fe321dda57b89ec4d797ec41624ae2477e47957f71cd4569f9c42fb592d5b1860037ba0fdf2378a75fbba2cf3ed894e1c3da
6
+ metadata.gz: 742b224bdcd584ef89677e7e072a07c55c975604ed64eb9aa369996e71588b8e980a5503441ddd8787d3c1bc348af0b5d28ce20159c3e06a8930ab712c42c031
7
+ data.tar.gz: e3ef7c4c71295ce9c03f17b74570234feae6e27d9a1a278478e0c851e9f98f5d8ea82c4e4c1272cf97a52858aa83af0e47abeac9b541c08afd5f1eacc9890a69
data/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ minor versions may contain breaking changes.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.8.0] - 2026-10-12
11
+
12
+ ### Added
13
+
14
+ - Client: `method_retries:` sets retry policies per service
15
+ (`"demo.v1.ItemService"`) or per method
16
+ (`"demo.v1.ItemService/GetItem"`), like gRPC's service config. The most
17
+ specific setting wins: the call's `retries:`, then the method, then the
18
+ service, then the client's `retries:`.
19
+
20
+ ### Fixed
21
+
22
+ - Windows: the process could crash with a segfault under load (#41). The
23
+ extension's locks spun and then called `Sleep`, which the mingw linker
24
+ bound to the `Sleep` that Ruby's DLL exports instead of the system's,
25
+ and Ruby's version crashes on threads Ruby doesn't own. Locks now come
26
+ from Rust's standard library, which doesn't spin through `Sleep`, the
27
+ build binds `Sleep` to kernel32, and CI checks that the Windows build
28
+ imports nothing but Ruby's C API from Ruby's DLL. 0.6.0 and 0.7.0 crashed in about 1 in 5 runs of the test suite;
29
+ earlier versions could crash in the same way, but rarely.
30
+
10
31
  ## [0.7.0] - 2026-10-11
11
32
 
12
33
  ### Added
@@ -186,7 +207,8 @@ First public release.
186
207
  - Precompiled native gems for Linux (x86_64, aarch64; glibc and musl) and
187
208
  macOS (x86_64, arm64), Ruby 3.3 to 4.0.
188
209
 
189
- [Unreleased]: https://github.com/CodingAnarchy/tonic-rails/compare/v0.7.0...HEAD
210
+ [Unreleased]: https://github.com/CodingAnarchy/tonic-rails/compare/v0.8.0...HEAD
211
+ [0.8.0]: https://github.com/CodingAnarchy/tonic-rails/compare/v0.7.0...v0.8.0
190
212
  [0.7.0]: https://github.com/CodingAnarchy/tonic-rails/compare/v0.6.0...v0.7.0
191
213
  [0.6.0]: https://github.com/CodingAnarchy/tonic-rails/compare/v0.5.0...v0.6.0
192
214
  [0.5.0]: https://github.com/CodingAnarchy/tonic-rails/compare/v0.4.0...v0.5.0
data/README.md CHANGED
@@ -518,6 +518,24 @@ items.get_item({ id: 1 }, retries: false) # not this call
518
518
  items.get_item({ id: 1 }, retries: { max_attempts: 5 }) # or differently
519
519
  ```
520
520
 
521
+ Different methods often need different policies: a read can retry more
522
+ eagerly than a write. `method_retries:` sets them per service or per
523
+ method, by their protobuf names:
524
+
525
+ ```ruby
526
+ ITEMS = Tonic::Rails::Client.new(
527
+ "items.internal:50051",
528
+ retries: true, # every call...
529
+ method_retries: {
530
+ "demo.v1.ItemService/GetItem" => { max_attempts: 5 }, # ...but this method,
531
+ "demo.v1.AdminService" => false, # and this whole service
532
+ },
533
+ )
534
+ ```
535
+
536
+ The most specific setting wins: the call's own `retries:`, then its
537
+ method's entry, then its service's, then the client's `retries:`.
538
+
521
539
  `retries: true` tries a call up to 3 times when it fails with
522
540
  `UNAVAILABLE`. A Hash changes any of these:
523
541
 
@@ -612,6 +630,7 @@ the client is created, not on the first call.
612
630
  | `max_message_size` | 4 MiB | largest message sent or received |
613
631
  | `connect_timeout` | 5 | seconds to wait for a connection |
614
632
  | `retries` | `false` | retry calls the server never started on; see [Retries](#retries) |
633
+ | `method_retries` | `{}` | retries per service or method, by name |
615
634
  | `logger` | `Tonic::Rails.configuration.logger` | where retries are logged |
616
635
 
617
636
  ### Fork safety
@@ -16,6 +16,7 @@ module Tonic
16
16
  #
17
17
  # Retries are opt-in: `retries: true` (or a Hash; see RetryPolicy) on
18
18
  # the client or a call retries calls the server never started on.
19
+ # `method_retries:` sets them per service or method.
19
20
  #
20
21
  # Stubs are built from the protobuf descriptors that
21
22
  # `tonic_rails:compile_protos` (protoc --ruby_out) generates; no
@@ -46,6 +47,10 @@ module Tonic
46
47
  # @return [RetryPolicy, nil] how calls are retried, unless they say otherwise
47
48
  attr_reader :retries
48
49
 
50
+ # @return [Hash{String=>RetryPolicy, nil}] retry policies by service or
51
+ # method name, which take precedence over #retries
52
+ attr_reader :method_retries
53
+
49
54
  # @param address [String] "host:port"
50
55
  # @param tls [Boolean] false for plaintext, which must be explicit
51
56
  # @param tls_ca_path [String, nil] CA certificates (PEM) to trust instead
@@ -61,11 +66,15 @@ module Tonic
61
66
  # @param connect_timeout [Numeric] seconds to wait for a connection
62
67
  # @param retries [RetryPolicy, Hash, Boolean] retry calls the server
63
68
  # never started on (see RetryPolicy); off by default
69
+ # @param method_retries [Hash{String=>RetryPolicy, Hash, Boolean}]
70
+ # retries for some services ("demo.v1.ItemService") or methods
71
+ # ("demo.v1.ItemService/GetItem"), instead of `retries`. A method's
72
+ # entry beats its service's.
64
73
  # @param logger [Logger, nil] where retries are logged; defaults to
65
74
  # Tonic::Rails.configuration.logger
66
75
  def initialize(address, tls: true, tls_ca_path: nil, tls_cert_path: nil, tls_key_path: nil,
67
76
  tls_server_name: nil, deadline: nil, metadata: {}, max_message_size: DEFAULT_MAX_MESSAGE_SIZE,
68
- connect_timeout: 5, retries: false, logger: nil)
77
+ connect_timeout: 5, retries: false, method_retries: {}, logger: nil)
69
78
  Tonic::Rails.native_extension!
70
79
  validate_address!(address)
71
80
  validate_tls!(tls, tls_cert_path, tls_key_path)
@@ -78,6 +87,7 @@ module Tonic
78
87
  @address = address
79
88
  @deadline = deadline
80
89
  @retries = RetryPolicy.from(retries)
90
+ @method_retries = method_retry_policies(method_retries)
81
91
  @logger = logger
82
92
  @metadata = Metadata.encode(metadata)
83
93
  @stubs = {}
@@ -127,7 +137,7 @@ module Tonic
127
137
  bytes = input.encode(request_message(path, input, request))
128
138
  metadata = call_metadata(metadata)
129
139
  deadline_at = deadline_at(deadline)
130
- policy = retry_policy(retries)
140
+ policy = retry_policy(path, retries)
131
141
 
132
142
  Instrumentation.instrument_request(path, address, metadata) do |payload|
133
143
  code, error_message, response, headers, trailers, details = with_retries(path, policy, deadline_at, payload) do
@@ -150,7 +160,7 @@ module Tonic
150
160
  # Fixed now, so the stream keeps the deadline of the RPC this
151
161
  # thread is handling even if it's read later.
152
162
  deadline_at = deadline_at(deadline)
153
- policy = retry_policy(retries)
163
+ policy = retry_policy(path, retries)
154
164
 
155
165
  ServerStream.new(path) do |stream, block|
156
166
  Instrumentation.instrument_request(path, address, metadata) do |payload|
@@ -238,8 +248,35 @@ module Tonic
238
248
  (remaining * 1000).ceil
239
249
  end
240
250
 
241
- def retry_policy(retries)
242
- retries.nil? ? @retries : RetryPolicy.from(retries)
251
+ METHOD_NAME = %r{\A[A-Za-z_][\w.]*(/[A-Za-z_]\w*)?\z}
252
+ private_constant :METHOD_NAME
253
+
254
+ def method_retry_policies(option)
255
+ raise ArgumentError, "method_retries must be a Hash" unless option.is_a?(Hash)
256
+
257
+ option.to_h do |name, retries|
258
+ name = name.to_s.delete_prefix("/")
259
+ unless name.match?(METHOD_NAME)
260
+ raise ArgumentError, "method_retries keys must be \"package.Service\" or \"package.Service/Method\", " \
261
+ "got #{name.inspect}"
262
+ end
263
+
264
+ [name, RetryPolicy.from(retries)]
265
+ end.freeze
266
+ end
267
+
268
+ # The most specific policy for a call: its own, its method's, its
269
+ # service's, then the client's.
270
+ def retry_policy(path, retries)
271
+ return RetryPolicy.from(retries) unless retries.nil?
272
+ return @retries if @method_retries.empty?
273
+
274
+ method = path.delete_prefix("/")
275
+ service = method.split("/", 2).first
276
+ return @method_retries[method] if @method_retries.key?(method)
277
+ return @method_retries[service] if @method_retries.key?(service)
278
+
279
+ @retries
243
280
  end
244
281
 
245
282
  # Yield each message of a native stream, then return its result.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Tonic
4
4
  module Rails
5
- VERSION = "0.7.0"
5
+ VERSION = "0.8.0"
6
6
  end
7
7
  end
data/lib/tonic-rails.rb CHANGED
@@ -81,11 +81,13 @@ module Tonic
81
81
  # Precompiled platform gems ship one binary per Ruby minor version.
82
82
  ruby_version = RUBY_VERSION[/\d+\.\d+/]
83
83
  require "tonic/rails/#{ruby_version}/tonic_rails_native"
84
- rescue LoadError
84
+ rescue LoadError => versioned
85
85
  begin
86
86
  require "tonic/rails/tonic_rails_native"
87
87
  rescue LoadError => e
88
- @native_load_error = e
88
+ # A precompiled binary that exists but won't load says more than
89
+ # the missing fallback does.
90
+ @native_load_error = versioned.message.include?("cannot load such file") ? e : versioned
89
91
  end
90
92
  end
91
93
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tonic-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: x86_64-linux-gnu
6
6
  authors:
7
7
  - Matt Tanous
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-11 00:00:00.000000000 Z
11
+ date: 2026-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport