async-grpc 0.7.0 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13df5d80dfc403580a0b3efa15de081d71f285901a5f082bacb7cb840b23f66f
4
- data.tar.gz: 59f811ca32b0beac56192f587be2e3184279c5d9160891b9b931b20229473033
3
+ metadata.gz: 2b2db42e03f75834e2259977d953d8c1688949e3c45c3ca972f9a9a0c6ca23b9
4
+ data.tar.gz: 1f7ce2103876bcb8fe0d716595668bee4904e1d2f35d0cb5ac86b246f84fd2e0
5
5
  SHA512:
6
- metadata.gz: 2d85ab093902e64a2ea3877f788eeac19bd6ae005bf47d3ddfa52831d0fa8193255f6ae0158b7bbb6897f4f5cdd39935cf03d7b14b9139da8257ffef07e1258e
7
- data.tar.gz: ee29fe46cf81d22298c94c5cb63b17a4783e4159f6110f70efc91444d507f47aec2bf14346d7e6187b9b40bee3f18a1e38c511afc0250c3f2fadbf88790495b7
6
+ metadata.gz: 61cfba13b45b83a390b41e2ede94ad6bf81286f3273630d8bc8336103e40d888fbb0d0c74f1f54c04c44d37a19fa493fcb0cf29e096388d855ff3b7fb626d187
7
+ data.tar.gz: 46dc51138f257f1768ddef3d81b42d1c040a53812a9970bd8bb7fee60a94a6e0d16f210069faa4c6b484f58994070f1e9ad04459685f57932fa89db40eb5bf8c
checksums.yaml.gz.sig CHANGED
Binary file
@@ -16,7 +16,7 @@ require "protocol/grpc/body/writable_body"
16
16
  require "protocol/grpc/metadata"
17
17
  require "protocol/grpc/error"
18
18
  require_relative "stub"
19
- require_relative "remote_error"
19
+ require_relative "error"
20
20
 
21
21
  module Async
22
22
  module GRPC
@@ -4,7 +4,8 @@
4
4
  # Copyright, 2025-2026, by Samuel Williams.
5
5
 
6
6
  require "async"
7
- require "async/deadline"
7
+
8
+ require_relative "error"
8
9
 
9
10
  require "protocol/grpc/middleware"
10
11
  require "protocol/grpc/methods"
@@ -44,6 +45,25 @@ module Async
44
45
 
45
46
  protected
46
47
 
48
+ # Invoke a service handler, providing a protected extension point for middleware and instrumentation around service execution.
49
+ #
50
+ # Override this method to observe service outcomes, establish request context, or wrap handlers with application middleware. Overrides should call `super` to invoke the handler and preserve the dispatcher's stream cleanup, trailer handling, and successful status assignment.
51
+ #
52
+ # This hook only surrounds service handler execution. Errors raised earlier while routing or preparing the request do not pass through it. A call deadline that expires during service execution raises {DeadlineExceededError} through this hook before the dispatcher converts it to a `DEADLINE_EXCEEDED` response.
53
+ #
54
+ # @parameter service [Async::GRPC::Service] The service containing the handler.
55
+ # @parameter handler_method [Symbol] The service method to invoke.
56
+ # @parameter input [Protocol::GRPC::Body::ReadableBody] The decoded request stream.
57
+ # @parameter output [Protocol::GRPC::Body::WritableBody] The response stream.
58
+ # @parameter call [Protocol::GRPC::Call] The call context.
59
+ # @returns [Object | Nil] An internal dispatch result with no stable application-facing contract.
60
+ # @example Wrap service execution with application middleware
61
+ # def invoke_service(service, handler_method, input, output, call)
62
+ # context = RequestContext.new(call.request)
63
+ # middleware.call(context) do
64
+ # super
65
+ # end
66
+ # end
47
67
  def invoke_service(service, handler_method, input, output, call)
48
68
  begin
49
69
  service.send(handler_method, input, output, call)
@@ -69,15 +89,15 @@ module Async
69
89
  end
70
90
  end
71
91
 
72
- def dispatch_to_service(service, handler_method, input, output, call, deadline, parent: Async::Task.current)
73
- if deadline
74
- parent.with_timeout(deadline.remaining) do
92
+ def dispatch_to_service(service, handler_method, input, output, call, parent: Async::Task.current)
93
+ if deadline = call.deadline
94
+ parent.with_timeout(deadline.remaining, DeadlineExceededError) do
75
95
  invoke_service(service, handler_method, input, output, call)
76
96
  end
77
97
  else
78
98
  invoke_service(service, handler_method, input, output, call)
79
99
  end
80
- rescue Async::TimeoutError => error
100
+ rescue DeadlineExceededError => error
81
101
  # Close input and output streams:
82
102
  input.close
83
103
  output.close_write unless output.closed?
@@ -135,22 +155,16 @@ module Async
135
155
  # Create response object:
136
156
  response = Protocol::HTTP::Response[200, response_headers, output]
137
157
 
138
- # Parse deadline from timeout header:
139
- timeout = Protocol::GRPC::Methods.parse_timeout(request.headers["grpc-timeout"])
140
- deadline = if timeout
141
- Async::Deadline.start(timeout)
142
- end
143
-
144
- # Create call context with request and response:
145
- call = Protocol::GRPC::Call.new(request, response, deadline: deadline)
158
+ # Create call context with request, response and deadline:
159
+ call = Protocol::GRPC::Call.for(request, response)
146
160
 
147
161
  if rpc_descriptor.streaming?
148
162
  Async do |task|
149
- dispatch_to_service(service, handler_method, input, output, call, deadline, parent: task)
163
+ dispatch_to_service(service, handler_method, input, output, call, parent: task)
150
164
  end
151
165
  else
152
166
  # Unary call:
153
- dispatch_to_service(service, handler_method, input, output, call, deadline)
167
+ dispatch_to_service(service, handler_method, input, output, call)
154
168
  end
155
169
 
156
170
  return response
@@ -5,10 +5,18 @@
5
5
 
6
6
  module Async
7
7
  module GRPC
8
+ # Represents a generic async gRPC error.
9
+ class Error < StandardError
10
+ end
11
+
12
+ # Raised when a gRPC call exceeds its deadline.
13
+ class DeadlineExceededError < Error
14
+ end
15
+
8
16
  # Represents an error that originated from a remote gRPC server.
9
17
  # Used as the `cause` of {Protocol::GRPC::Error} when the client receives a non-OK status.
10
18
  # The message and optional backtrace are extracted from response metadata.
11
- class RemoteError < StandardError
19
+ class RemoteError < Error
12
20
  # Create a RemoteError from server response metadata.
13
21
  # @parameter message [String | Nil] The error message from `grpc-message` header.
14
22
  # @parameter metadata [Hash] Response metadata (extracted from gRPC headers). If it contains a `"backtrace"` key (array of strings), it is set on the error and removed from the hash.
@@ -7,7 +7,7 @@
7
7
  module Async
8
8
  # @namespace
9
9
  module GRPC
10
- VERSION = "0.7.0"
10
+ VERSION = "0.8.0"
11
11
  end
12
12
  end
13
13
 
data/lib/async/grpc.rb CHANGED
@@ -4,6 +4,7 @@
4
4
  # Copyright, 2025, by Samuel Williams.
5
5
 
6
6
  require_relative "grpc/version"
7
+ require_relative "grpc/error"
7
8
  require_relative "grpc/client"
8
9
  require_relative "grpc/service"
9
10
  require_relative "grpc/stub"
data/readme.md CHANGED
@@ -24,6 +24,10 @@ Please see the [project documentation](https://socketry.github.io/async-grpc/) f
24
24
 
25
25
  Please see the [project releases](https://socketry.github.io/async-grpc/releases/index) for all releases.
26
26
 
27
+ ### v0.8.0
28
+
29
+ - Added `Async::GRPC::Error` as the base class for async gRPC errors, including `RemoteError` and the new `DeadlineExceededError` used to distinguish call deadline expiry from unrelated `Async::TimeoutError` failures.
30
+
27
31
  ### v0.6.0
28
32
 
29
33
  - Ensure `grpc-status` (and related metadata) is sent as a trailer, if data frames are written.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.8.0
4
+
5
+ - Added `Async::GRPC::Error` as the base class for async gRPC errors, including `RemoteError` and the new `DeadlineExceededError` used to distinguish call deadline expiry from unrelated `Async::TimeoutError` failures.
6
+
3
7
  ## v0.6.0
4
8
 
5
9
  - Ensure `grpc-status` (and related metadata) is sent as a trailer, if data frames are written.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-grpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -38,6 +38,20 @@ cert_chain:
38
38
  -----END CERTIFICATE-----
39
39
  date: 1980-01-02 00:00:00.000000000 Z
40
40
  dependencies:
41
+ - !ruby/object:Gem::Dependency
42
+ name: async
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 2.38.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.38.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: async-http
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +72,14 @@ dependencies:
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: 0.11.0
75
+ version: 0.12.0
62
76
  type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: 0.11.0
82
+ version: 0.12.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: protocol-http
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -90,7 +104,7 @@ files:
90
104
  - lib/async/grpc.rb
91
105
  - lib/async/grpc/client.rb
92
106
  - lib/async/grpc/dispatcher.rb
93
- - lib/async/grpc/remote_error.rb
107
+ - lib/async/grpc/error.rb
94
108
  - lib/async/grpc/service.rb
95
109
  - lib/async/grpc/stub.rb
96
110
  - lib/async/grpc/version.rb
metadata.gz.sig CHANGED
Binary file