restate-sdk 0.7.0-aarch64-linux → 0.9.0-aarch64-linux
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 +4 -4
- data/Cargo.lock +1 -1
- data/README.md +15 -10
- data/ext/restate_internal/Cargo.toml +1 -1
- data/lib/restate/3.2/restate_internal.so +0 -0
- data/lib/restate/3.3/restate_internal.so +0 -0
- data/lib/restate/3.4/restate_internal.so +0 -0
- data/lib/restate/4.0/restate_internal.so +0 -0
- data/lib/restate/client.rb +5 -29
- data/lib/restate/config.rb +4 -11
- data/lib/restate/context.rb +13 -128
- data/lib/restate/discovery.rb +6 -15
- data/lib/restate/durable_future.rb +15 -39
- data/lib/restate/endpoint.rb +61 -48
- data/lib/restate/errors.rb +2 -15
- data/lib/restate/handler.rb +21 -21
- data/lib/restate/serde.rb +14 -130
- data/lib/restate/server.rb +12 -27
- data/lib/restate/server_context.rb +111 -276
- data/lib/restate/service.rb +2 -3
- data/lib/restate/service_dsl.rb +8 -8
- data/lib/restate/service_proxy.rb +2 -13
- data/lib/restate/testing.rb +1 -1
- data/lib/restate/version.rb +2 -2
- data/lib/restate/virtual_object.rb +3 -4
- data/lib/restate/vm.rb +9 -74
- data/lib/restate/workflow.rb +3 -4
- data/lib/restate.rb +4 -93
- data/sig/restate.rbs +202 -0
- metadata +3 -18
- data/lib/tapioca/dsl/compilers/restate.rb +0 -115
- data/rbi/restate-sdk.rbi +0 -582
|
@@ -5,24 +5,19 @@ module Restate
|
|
|
5
5
|
# A durable future wrapping a VM handle. Lazily resolves on first +await+ and caches the result.
|
|
6
6
|
# Returned by +ctx.run+ and +ctx.sleep+.
|
|
7
7
|
class DurableFuture
|
|
8
|
-
extend T::Sig
|
|
9
|
-
|
|
10
|
-
sig { returns(Integer) }
|
|
11
8
|
attr_reader :handle
|
|
12
9
|
|
|
13
|
-
sig { params(ctx: ServerContext, handle: Integer, serde: T.untyped).void }
|
|
14
10
|
def initialize(ctx, handle, serde: nil)
|
|
15
|
-
@ctx =
|
|
16
|
-
@handle =
|
|
17
|
-
@serde =
|
|
18
|
-
@resolved =
|
|
19
|
-
@value =
|
|
11
|
+
@ctx = ctx
|
|
12
|
+
@handle = handle
|
|
13
|
+
@serde = serde
|
|
14
|
+
@resolved = false
|
|
15
|
+
@value = nil
|
|
20
16
|
end
|
|
21
17
|
|
|
22
18
|
# Block until the result is available and return it. Caches across calls.
|
|
23
19
|
#
|
|
24
20
|
# @return [Object] the deserialized result
|
|
25
|
-
sig { returns(T.untyped) }
|
|
26
21
|
def await
|
|
27
22
|
unless @resolved
|
|
28
23
|
raw = @ctx.resolve_handle(@handle)
|
|
@@ -35,7 +30,6 @@ module Restate
|
|
|
35
30
|
# Check whether the future has completed (non-blocking).
|
|
36
31
|
#
|
|
37
32
|
# @return [Boolean]
|
|
38
|
-
sig { returns(T::Boolean) }
|
|
39
33
|
def completed?
|
|
40
34
|
@resolved || @ctx.completed?(@handle)
|
|
41
35
|
end
|
|
@@ -45,26 +39,15 @@ module Restate
|
|
|
45
39
|
# Adds +invocation_id+ and +cancel+ on top of DurableFuture.
|
|
46
40
|
# Returned by +ctx.service_call+, +ctx.object_call+, +ctx.workflow_call+.
|
|
47
41
|
class DurableCallFuture < DurableFuture
|
|
48
|
-
extend T::Sig
|
|
49
|
-
|
|
50
|
-
sig do
|
|
51
|
-
params(
|
|
52
|
-
ctx: ServerContext,
|
|
53
|
-
result_handle: Integer,
|
|
54
|
-
invocation_id_handle: Integer,
|
|
55
|
-
output_serde: T.untyped
|
|
56
|
-
).void
|
|
57
|
-
end
|
|
58
42
|
def initialize(ctx, result_handle, invocation_id_handle, output_serde:)
|
|
59
43
|
super(ctx, result_handle)
|
|
60
|
-
@invocation_id_handle =
|
|
61
|
-
@output_serde =
|
|
62
|
-
@invocation_id_resolved =
|
|
63
|
-
@invocation_id_value =
|
|
44
|
+
@invocation_id_handle = invocation_id_handle
|
|
45
|
+
@output_serde = output_serde
|
|
46
|
+
@invocation_id_resolved = false
|
|
47
|
+
@invocation_id_value = nil
|
|
64
48
|
end
|
|
65
49
|
|
|
66
50
|
# Block until the result is available and return it. Deserializes via +output_serde+.
|
|
67
|
-
sig { returns(T.untyped) }
|
|
68
51
|
def await
|
|
69
52
|
unless @resolved
|
|
70
53
|
raw = @ctx.resolve_handle(@handle)
|
|
@@ -81,17 +64,15 @@ module Restate
|
|
|
81
64
|
# Returns the invocation ID of the remote call. Lazily resolved.
|
|
82
65
|
#
|
|
83
66
|
# @return [String] the invocation ID
|
|
84
|
-
sig { returns(String) }
|
|
85
67
|
def invocation_id
|
|
86
68
|
unless @invocation_id_resolved
|
|
87
69
|
@invocation_id_value = @ctx.resolve_handle(@invocation_id_handle)
|
|
88
70
|
@invocation_id_resolved = true
|
|
89
71
|
end
|
|
90
|
-
|
|
72
|
+
@invocation_id_value
|
|
91
73
|
end
|
|
92
74
|
|
|
93
75
|
# Cancel the remote invocation.
|
|
94
|
-
sig { void }
|
|
95
76
|
def cancel
|
|
96
77
|
@ctx.cancel_invocation(invocation_id)
|
|
97
78
|
end
|
|
@@ -100,30 +81,25 @@ module Restate
|
|
|
100
81
|
# A handle for fire-and-forget send operations.
|
|
101
82
|
# Returned by +ctx.service_send+, +ctx.object_send+, +ctx.workflow_send+.
|
|
102
83
|
class SendHandle
|
|
103
|
-
extend T::Sig
|
|
104
|
-
|
|
105
|
-
sig { params(ctx: ServerContext, invocation_id_handle: Integer).void }
|
|
106
84
|
def initialize(ctx, invocation_id_handle)
|
|
107
|
-
@ctx =
|
|
108
|
-
@invocation_id_handle =
|
|
109
|
-
@invocation_id_resolved =
|
|
110
|
-
@invocation_id_value =
|
|
85
|
+
@ctx = ctx
|
|
86
|
+
@invocation_id_handle = invocation_id_handle
|
|
87
|
+
@invocation_id_resolved = false
|
|
88
|
+
@invocation_id_value = nil
|
|
111
89
|
end
|
|
112
90
|
|
|
113
91
|
# Returns the invocation ID of the sent call. Lazily resolved.
|
|
114
92
|
#
|
|
115
93
|
# @return [String] the invocation ID
|
|
116
|
-
sig { returns(String) }
|
|
117
94
|
def invocation_id
|
|
118
95
|
unless @invocation_id_resolved
|
|
119
96
|
@invocation_id_value = @ctx.resolve_handle(@invocation_id_handle)
|
|
120
97
|
@invocation_id_resolved = true
|
|
121
98
|
end
|
|
122
|
-
|
|
99
|
+
@invocation_id_value
|
|
123
100
|
end
|
|
124
101
|
|
|
125
102
|
# Cancel the remote invocation.
|
|
126
|
-
sig { void }
|
|
127
103
|
def cancel
|
|
128
104
|
@ctx.cancel_invocation(invocation_id)
|
|
129
105
|
end
|
data/lib/restate/endpoint.rb
CHANGED
|
@@ -4,26 +4,16 @@
|
|
|
4
4
|
module Restate
|
|
5
5
|
# Container for registered services. Bind services here, then create the Rack app.
|
|
6
6
|
class Endpoint
|
|
7
|
-
|
|
7
|
+
attr_reader :services, :identity_keys, :middleware, :outbound_middleware
|
|
8
8
|
|
|
9
|
-
sig { returns(T::Hash[String, T.untyped]) }
|
|
10
|
-
attr_reader :services
|
|
11
|
-
|
|
12
|
-
sig { returns(T::Array[String]) }
|
|
13
|
-
attr_reader :identity_keys
|
|
14
|
-
|
|
15
|
-
sig { returns(T.nilable(String)) }
|
|
16
9
|
attr_accessor :protocol
|
|
17
10
|
|
|
18
|
-
sig { returns(T::Array[T.untyped]) }
|
|
19
|
-
attr_reader :middleware
|
|
20
|
-
|
|
21
|
-
sig { void }
|
|
22
11
|
def initialize
|
|
23
|
-
@services =
|
|
24
|
-
@protocol =
|
|
25
|
-
@identity_keys =
|
|
26
|
-
@middleware =
|
|
12
|
+
@services = {}
|
|
13
|
+
@protocol = nil
|
|
14
|
+
@identity_keys = []
|
|
15
|
+
@middleware = []
|
|
16
|
+
@outbound_middleware = []
|
|
27
17
|
end
|
|
28
18
|
|
|
29
19
|
# Bind one or more services to this endpoint.
|
|
@@ -31,7 +21,6 @@ module Restate
|
|
|
31
21
|
# @param svcs [Array<Class<Service>, Class<VirtualObject>, Class<Workflow>>] services to bind
|
|
32
22
|
# @return [self]
|
|
33
23
|
# @raise [ArgumentError] if a service with the same name is already bound
|
|
34
|
-
sig { params(svcs: T.untyped).returns(T.self_type) }
|
|
35
24
|
def bind(*svcs)
|
|
36
25
|
svcs.each do |svc|
|
|
37
26
|
svc_name = svc.service_name
|
|
@@ -43,49 +32,42 @@ module Restate
|
|
|
43
32
|
end
|
|
44
33
|
|
|
45
34
|
# Force bidirectional streaming protocol.
|
|
46
|
-
sig { returns(T.self_type) }
|
|
47
35
|
def streaming_protocol
|
|
48
36
|
@protocol = 'bidi'
|
|
49
37
|
self
|
|
50
38
|
end
|
|
51
39
|
|
|
52
40
|
# Force request/response protocol.
|
|
53
|
-
sig { returns(T.self_type) }
|
|
54
41
|
def request_response_protocol
|
|
55
42
|
@protocol = 'request_response'
|
|
56
43
|
self
|
|
57
44
|
end
|
|
58
45
|
|
|
59
46
|
# Add an identity key for request verification.
|
|
60
|
-
sig { params(key: String).returns(T.self_type) }
|
|
61
47
|
def identity_key(key)
|
|
62
48
|
@identity_keys << key
|
|
63
49
|
self
|
|
64
50
|
end
|
|
65
51
|
|
|
66
|
-
# Add
|
|
52
|
+
# Add inbound (server) middleware.
|
|
67
53
|
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
54
|
+
# Inbound middleware wraps every handler invocation, like
|
|
55
|
+
# {https://github.com/sidekiq/sidekiq/wiki/Middleware Sidekiq server middleware}.
|
|
70
56
|
#
|
|
71
57
|
# A middleware is a class whose instances respond to +call(handler, ctx)+.
|
|
72
58
|
# Use +yield+ inside +call+ to invoke the next middleware or the handler.
|
|
73
59
|
# The return value of +yield+ is the handler's return value.
|
|
74
60
|
#
|
|
75
|
-
# This follows the same pattern as {https://github.com/sidekiq/sidekiq/wiki/Middleware Sidekiq middleware}.
|
|
76
|
-
#
|
|
77
61
|
# @example OpenTelemetry tracing
|
|
78
|
-
# class
|
|
62
|
+
# class TracingMiddleware
|
|
79
63
|
# def call(handler, ctx)
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# }) do
|
|
84
|
-
# yield
|
|
64
|
+
# extracted = OpenTelemetry.propagation.extract(ctx.request.headers)
|
|
65
|
+
# OpenTelemetry::Context.with_current(extracted) do
|
|
66
|
+
# tracer.in_span(handler.name) { yield }
|
|
85
67
|
# end
|
|
86
68
|
# end
|
|
87
69
|
# end
|
|
88
|
-
# endpoint.use(
|
|
70
|
+
# endpoint.use(TracingMiddleware)
|
|
89
71
|
#
|
|
90
72
|
# @example Metrics
|
|
91
73
|
# class MetricsMiddleware
|
|
@@ -99,39 +81,70 @@ module Restate
|
|
|
99
81
|
# end
|
|
100
82
|
# endpoint.use(MetricsMiddleware)
|
|
101
83
|
#
|
|
102
|
-
# @
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
84
|
+
# @param klass [Class] middleware class (will be instantiated by the SDK)
|
|
85
|
+
# @param args [Array] positional arguments for the middleware constructor
|
|
86
|
+
# @param kwargs [Hash] keyword arguments for the middleware constructor
|
|
87
|
+
# @return [self]
|
|
88
|
+
def use(klass, *args, **kwargs)
|
|
89
|
+
@middleware << instantiate_middleware(klass, args, kwargs)
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Add outbound (client) middleware.
|
|
94
|
+
#
|
|
95
|
+
# Outbound middleware wraps every outgoing service call and send, like
|
|
96
|
+
# {https://github.com/sidekiq/sidekiq/wiki/Middleware Sidekiq client middleware}.
|
|
97
|
+
#
|
|
98
|
+
# A middleware is a class whose instances respond to +call(service, handler, headers)+.
|
|
99
|
+
# The +headers+ hash is mutable — modify it to attach headers to the outgoing
|
|
100
|
+
# request. Use +yield+ to continue the chain.
|
|
101
|
+
#
|
|
102
|
+
# Note: Restate automatically propagates inbound headers to outbound calls.
|
|
103
|
+
# Outbound middleware is for injecting *new* headers that aren't on the
|
|
104
|
+
# original request (e.g., tenant IDs from fiber-local storage, authorization
|
|
105
|
+
# tokens for specific target services).
|
|
106
|
+
#
|
|
107
|
+
# @example Propagate tenant ID to all outgoing calls
|
|
108
|
+
# class TenantOutboundMiddleware
|
|
109
|
+
# def call(_service, _handler, headers)
|
|
110
|
+
# headers['x-tenant-id'] = Thread.current[:tenant_id]
|
|
111
|
+
# yield
|
|
106
112
|
# end
|
|
113
|
+
# end
|
|
114
|
+
# endpoint.use_outbound(TenantOutboundMiddleware)
|
|
107
115
|
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
116
|
+
# @example Log all outgoing calls
|
|
117
|
+
# class OutboundLogger
|
|
118
|
+
# def call(service, handler, headers)
|
|
119
|
+
# logger.info("Calling #{service}/#{handler}")
|
|
110
120
|
# yield
|
|
111
121
|
# end
|
|
112
122
|
# end
|
|
113
|
-
# endpoint.
|
|
123
|
+
# endpoint.use_outbound(OutboundLogger)
|
|
114
124
|
#
|
|
115
125
|
# @param klass [Class] middleware class (will be instantiated by the SDK)
|
|
116
126
|
# @param args [Array] positional arguments for the middleware constructor
|
|
117
127
|
# @param kwargs [Hash] keyword arguments for the middleware constructor
|
|
118
128
|
# @return [self]
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
instance = if kwargs.empty?
|
|
122
|
-
klass.new(*args)
|
|
123
|
-
else
|
|
124
|
-
klass.new(*args, **kwargs)
|
|
125
|
-
end
|
|
126
|
-
@middleware << instance
|
|
129
|
+
def use_outbound(klass, *args, **kwargs)
|
|
130
|
+
@outbound_middleware << instantiate_middleware(klass, args, kwargs)
|
|
127
131
|
self
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
# Build and return the Rack-compatible application.
|
|
131
|
-
sig { returns(T.untyped) }
|
|
132
135
|
def app
|
|
133
136
|
require_relative 'server'
|
|
134
137
|
Server.new(self)
|
|
135
138
|
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def instantiate_middleware(klass, args, kwargs)
|
|
143
|
+
if kwargs.empty?
|
|
144
|
+
klass.new(*args)
|
|
145
|
+
else
|
|
146
|
+
klass.new(*args, **kwargs)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
136
149
|
end
|
|
137
150
|
end
|
data/lib/restate/errors.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
module Restate
|
|
@@ -7,24 +7,17 @@ module Restate
|
|
|
7
7
|
# @example
|
|
8
8
|
# raise Restate::TerminalError.new('not found', status_code: 404)
|
|
9
9
|
class TerminalError < StandardError
|
|
10
|
-
extend T::Sig
|
|
11
|
-
|
|
12
|
-
sig { returns(Integer) }
|
|
13
10
|
attr_reader :status_code
|
|
14
11
|
|
|
15
|
-
sig { params(message: String, status_code: Integer).void }
|
|
16
12
|
def initialize(message = 'Internal Server Error', status_code: 500)
|
|
17
13
|
super(message)
|
|
18
|
-
@status_code =
|
|
14
|
+
@status_code = status_code
|
|
19
15
|
end
|
|
20
16
|
end
|
|
21
17
|
|
|
22
18
|
# Internal: raised when the VM suspends execution.
|
|
23
19
|
# User code should NOT catch this.
|
|
24
20
|
class SuspendedError < StandardError
|
|
25
|
-
extend T::Sig
|
|
26
|
-
|
|
27
|
-
sig { void }
|
|
28
21
|
def initialize
|
|
29
22
|
super(
|
|
30
23
|
"Invocation got suspended, Restate will resume this invocation when progress can be made.\n" \
|
|
@@ -37,9 +30,6 @@ module Restate
|
|
|
37
30
|
|
|
38
31
|
# Internal: raised when the VM encounters a retryable error.
|
|
39
32
|
class InternalError < StandardError
|
|
40
|
-
extend T::Sig
|
|
41
|
-
|
|
42
|
-
sig { void }
|
|
43
33
|
def initialize
|
|
44
34
|
super(
|
|
45
35
|
"Invocation attempt raised a retryable error.\n" \
|
|
@@ -50,9 +40,6 @@ module Restate
|
|
|
50
40
|
|
|
51
41
|
# Internal: raised when the HTTP connection is lost.
|
|
52
42
|
class DisconnectedError < StandardError
|
|
53
|
-
extend T::Sig
|
|
54
|
-
|
|
55
|
-
sig { void }
|
|
56
43
|
def initialize
|
|
57
44
|
super('Disconnected. The connection to the restate server was lost. Restate will retry the attempt.')
|
|
58
45
|
end
|
data/lib/restate/handler.rb
CHANGED
|
@@ -27,39 +27,39 @@ module Restate
|
|
|
27
27
|
keyword_init: true
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
extend T::Sig
|
|
31
|
-
|
|
32
30
|
module_function
|
|
33
31
|
|
|
34
32
|
# Invoke a handler with the context and raw input bytes.
|
|
35
33
|
# The context is passed as the first argument to every handler.
|
|
36
34
|
# Middleware (if any) wraps the handler call.
|
|
37
35
|
# Returns raw output bytes.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
def invoke_handler(handler:, ctx:, in_buffer:, middleware: [])
|
|
37
|
+
out_arg = if middleware.empty?
|
|
38
|
+
invoke_handler_direct(handler, in_buffer)
|
|
39
|
+
else
|
|
40
|
+
invoke_handler_with_middleware(handler, ctx, in_buffer, middleware)
|
|
41
|
+
end
|
|
42
|
+
handler.handler_io.output_serde.serialize(out_arg)
|
|
41
43
|
end
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
end
|
|
50
|
-
handler.callable.call(in_arg)
|
|
51
|
-
else
|
|
52
|
-
handler.callable.call
|
|
44
|
+
|
|
45
|
+
def invoke_handler_direct(handler, in_buffer)
|
|
46
|
+
if handler.arity == 1
|
|
47
|
+
begin
|
|
48
|
+
in_arg = handler.handler_io.input_serde.deserialize(in_buffer)
|
|
49
|
+
rescue StandardError => e
|
|
50
|
+
Kernel.raise TerminalError, "Unable to parse input argument: #{e.message}"
|
|
53
51
|
end
|
|
52
|
+
handler.callable.call(in_arg)
|
|
53
|
+
else
|
|
54
|
+
handler.callable.call
|
|
54
55
|
end
|
|
56
|
+
end
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
def invoke_handler_with_middleware(handler, ctx, in_buffer, middleware)
|
|
59
|
+
call_handler = Kernel.proc { invoke_handler_direct(handler, in_buffer) }
|
|
58
60
|
chain = middleware.reverse.reduce(call_handler) do |nxt, mw|
|
|
59
61
|
Kernel.proc { mw.call(handler, ctx, &nxt) }
|
|
60
62
|
end
|
|
61
|
-
|
|
62
|
-
out_arg = chain.call
|
|
63
|
-
handler.handler_io.output_serde.serialize(out_arg)
|
|
63
|
+
chain.call
|
|
64
64
|
end
|
|
65
65
|
end
|