restate-sdk 0.8.0-aarch64-linux → 0.10.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 +9 -17
- data/ext/restate_internal/Cargo.toml +1 -1
- 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 +27 -0
- data/lib/restate/endpoint.rb +57 -27
- data/lib/restate/introspection.rb +127 -0
- data/lib/restate/railtie.rb +17 -0
- data/lib/restate/server.rb +2 -1
- data/lib/restate/server_context.rb +67 -34
- data/lib/restate/version.rb +1 -1
- data/lib/restate.rb +1 -0
- data/sig/restate.rbs +9 -0
- metadata +5 -4
- data/lib/restate/3.2/restate_internal.so +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 80a62b147724910e3329f4263e61a290ccc55e6f0c097ecc0fad4ece63ef2407
|
|
4
|
+
data.tar.gz: 33661eccbb66c39e1ca6c57ea735e4ef74fa79a712e05136c7d0624720484ba9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0b1fec80f09851613ccb2c4c04ec677566f845b47e51ae5a248d001e4fa9400ed096b574f475551ac3c29e9ca63775a27be799e9876dc2c49a5c4a45e06a466
|
|
7
|
+
data.tar.gz: 4bbacd32b9999dfdec05918bf7eddb191a2e472b20c977dbab6b898c2bf8b2a6e8600649b2a6bc86fd8072368deab819e96e7b64c642dd2d17434be6084845d2
|
data/Cargo.lock
CHANGED
|
@@ -31,16 +31,14 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|
|
31
31
|
|
|
32
32
|
[[package]]
|
|
33
33
|
name = "bindgen"
|
|
34
|
-
version = "0.
|
|
34
|
+
version = "0.72.1"
|
|
35
35
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
36
|
-
checksum = "
|
|
36
|
+
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
|
37
37
|
dependencies = [
|
|
38
38
|
"bitflags",
|
|
39
39
|
"cexpr",
|
|
40
40
|
"clang-sys",
|
|
41
41
|
"itertools 0.12.1",
|
|
42
|
-
"lazy_static",
|
|
43
|
-
"lazycell",
|
|
44
42
|
"proc-macro2",
|
|
45
43
|
"quote",
|
|
46
44
|
"regex",
|
|
@@ -278,12 +276,6 @@ version = "1.5.0"
|
|
|
278
276
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
279
277
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
280
278
|
|
|
281
|
-
[[package]]
|
|
282
|
-
name = "lazycell"
|
|
283
|
-
version = "1.3.0"
|
|
284
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
285
|
-
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|
286
|
-
|
|
287
279
|
[[package]]
|
|
288
280
|
name = "libc"
|
|
289
281
|
version = "0.2.183"
|
|
@@ -489,18 +481,18 @@ dependencies = [
|
|
|
489
481
|
|
|
490
482
|
[[package]]
|
|
491
483
|
name = "rb-sys"
|
|
492
|
-
version = "0.9.
|
|
484
|
+
version = "0.9.128"
|
|
493
485
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
494
|
-
checksum = "
|
|
486
|
+
checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
|
|
495
487
|
dependencies = [
|
|
496
488
|
"rb-sys-build",
|
|
497
489
|
]
|
|
498
490
|
|
|
499
491
|
[[package]]
|
|
500
492
|
name = "rb-sys-build"
|
|
501
|
-
version = "0.9.
|
|
493
|
+
version = "0.9.128"
|
|
502
494
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
503
|
-
checksum = "
|
|
495
|
+
checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
|
|
504
496
|
dependencies = [
|
|
505
497
|
"bindgen",
|
|
506
498
|
"lazy_static",
|
|
@@ -569,7 +561,7 @@ dependencies = [
|
|
|
569
561
|
|
|
570
562
|
[[package]]
|
|
571
563
|
name = "restate_internal"
|
|
572
|
-
version = "0.
|
|
564
|
+
version = "0.10.0"
|
|
573
565
|
dependencies = [
|
|
574
566
|
"magnus",
|
|
575
567
|
"rb-sys",
|
|
@@ -593,9 +585,9 @@ dependencies = [
|
|
|
593
585
|
|
|
594
586
|
[[package]]
|
|
595
587
|
name = "rustc-hash"
|
|
596
|
-
version = "
|
|
588
|
+
version = "2.1.2"
|
|
597
589
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
598
|
-
checksum = "
|
|
590
|
+
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
|
599
591
|
|
|
600
592
|
[[package]]
|
|
601
593
|
name = "rustversion"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/restate/client.rb
CHANGED
|
@@ -81,6 +81,33 @@ module Restate
|
|
|
81
81
|
post_admin("/restate/invocations/#{invocation_id}/kill", nil)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
# ── Introspection queries ──
|
|
85
|
+
|
|
86
|
+
# Execute a SQL query against Restate's introspection API (DataFusion).
|
|
87
|
+
# The admin API exposes system tables (sys_invocation, sys_journal, state,
|
|
88
|
+
# etc.) that can be queried with standard SQL.
|
|
89
|
+
#
|
|
90
|
+
# @param sql [String] a SQL query string
|
|
91
|
+
# @return [Array<Hash>] rows returned by the query
|
|
92
|
+
#
|
|
93
|
+
# @example
|
|
94
|
+
# client.execute_query("SELECT id, status FROM sys_invocation LIMIT 10")
|
|
95
|
+
def execute_query(sql) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
96
|
+
uri = URI("#{@admin_url}/query")
|
|
97
|
+
request = Net::HTTP::Post.new(uri)
|
|
98
|
+
request['Content-Type'] = 'application/json'
|
|
99
|
+
request['Accept'] = 'application/json'
|
|
100
|
+
@admin_headers.each { |k, v| request[k] = v }
|
|
101
|
+
request.body = JSON.generate({ query: sql })
|
|
102
|
+
response = Net::HTTP.start(uri.hostname, uri.port, # steep:ignore ArgumentTypeMismatch
|
|
103
|
+
use_ssl: uri.scheme == 'https',
|
|
104
|
+
open_timeout: 5,
|
|
105
|
+
read_timeout: 30) { |http| http.request(request) }
|
|
106
|
+
Kernel.raise "Restate query error: #{response.code} #{response.body}" unless response.is_a?(Net::HTTPSuccess)
|
|
107
|
+
body = response.body
|
|
108
|
+
body && !body.empty? ? (JSON.parse(body)['rows'] || []) : []
|
|
109
|
+
end
|
|
110
|
+
|
|
84
111
|
private
|
|
85
112
|
|
|
86
113
|
def resolve_name(service)
|
data/lib/restate/endpoint.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module Restate
|
|
5
5
|
# Container for registered services. Bind services here, then create the Rack app.
|
|
6
6
|
class Endpoint
|
|
7
|
-
attr_reader :services, :identity_keys, :middleware
|
|
7
|
+
attr_reader :services, :identity_keys, :middleware, :outbound_middleware
|
|
8
8
|
|
|
9
9
|
attr_accessor :protocol
|
|
10
10
|
|
|
@@ -13,6 +13,7 @@ module Restate
|
|
|
13
13
|
@protocol = nil
|
|
14
14
|
@identity_keys = []
|
|
15
15
|
@middleware = []
|
|
16
|
+
@outbound_middleware = []
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# Bind one or more services to this endpoint.
|
|
@@ -48,29 +49,25 @@ module Restate
|
|
|
48
49
|
self
|
|
49
50
|
end
|
|
50
51
|
|
|
51
|
-
# Add
|
|
52
|
+
# Add inbound (server) middleware.
|
|
52
53
|
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
54
|
+
# Inbound middleware wraps every handler invocation, like
|
|
55
|
+
# {https://github.com/sidekiq/sidekiq/wiki/Middleware Sidekiq server middleware}.
|
|
55
56
|
#
|
|
56
57
|
# A middleware is a class whose instances respond to +call(handler, ctx)+.
|
|
57
58
|
# Use +yield+ inside +call+ to invoke the next middleware or the handler.
|
|
58
59
|
# The return value of +yield+ is the handler's return value.
|
|
59
60
|
#
|
|
60
|
-
# This follows the same pattern as {https://github.com/sidekiq/sidekiq/wiki/Middleware Sidekiq middleware}.
|
|
61
|
-
#
|
|
62
61
|
# @example OpenTelemetry tracing
|
|
63
|
-
# class
|
|
62
|
+
# class TracingMiddleware
|
|
64
63
|
# def call(handler, ctx)
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# }) do
|
|
69
|
-
# yield
|
|
64
|
+
# extracted = OpenTelemetry.propagation.extract(ctx.request.headers)
|
|
65
|
+
# OpenTelemetry::Context.with_current(extracted) do
|
|
66
|
+
# tracer.in_span(handler.name) { yield }
|
|
70
67
|
# end
|
|
71
68
|
# end
|
|
72
69
|
# end
|
|
73
|
-
# endpoint.use(
|
|
70
|
+
# endpoint.use(TracingMiddleware)
|
|
74
71
|
#
|
|
75
72
|
# @example Metrics
|
|
76
73
|
# class MetricsMiddleware
|
|
@@ -84,30 +81,53 @@ module Restate
|
|
|
84
81
|
# end
|
|
85
82
|
# endpoint.use(MetricsMiddleware)
|
|
86
83
|
#
|
|
87
|
-
# @
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
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
|
|
91
112
|
# end
|
|
113
|
+
# end
|
|
114
|
+
# endpoint.use_outbound(TenantOutboundMiddleware)
|
|
92
115
|
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
116
|
+
# @example Log all outgoing calls
|
|
117
|
+
# class OutboundLogger
|
|
118
|
+
# def call(service, handler, headers)
|
|
119
|
+
# logger.info("Calling #{service}/#{handler}")
|
|
95
120
|
# yield
|
|
96
121
|
# end
|
|
97
122
|
# end
|
|
98
|
-
# endpoint.
|
|
123
|
+
# endpoint.use_outbound(OutboundLogger)
|
|
99
124
|
#
|
|
100
125
|
# @param klass [Class] middleware class (will be instantiated by the SDK)
|
|
101
126
|
# @param args [Array] positional arguments for the middleware constructor
|
|
102
127
|
# @param kwargs [Hash] keyword arguments for the middleware constructor
|
|
103
128
|
# @return [self]
|
|
104
|
-
def
|
|
105
|
-
|
|
106
|
-
klass.new(*args)
|
|
107
|
-
else
|
|
108
|
-
klass.new(*args, **kwargs)
|
|
109
|
-
end
|
|
110
|
-
@middleware << instance
|
|
129
|
+
def use_outbound(klass, *args, **kwargs)
|
|
130
|
+
@outbound_middleware << instantiate_middleware(klass, args, kwargs)
|
|
111
131
|
self
|
|
112
132
|
end
|
|
113
133
|
|
|
@@ -116,5 +136,15 @@ module Restate
|
|
|
116
136
|
require_relative 'server'
|
|
117
137
|
Server.new(self)
|
|
118
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
|
|
119
149
|
end
|
|
120
150
|
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'active_record'
|
|
5
|
+
|
|
6
|
+
module Restate
|
|
7
|
+
# Arel table references for Restate's SQL introspection tables.
|
|
8
|
+
#
|
|
9
|
+
# Restate exposes a DataFusion-powered SQL endpoint at +/query+ on the admin
|
|
10
|
+
# API. These tables let you build queries using Arel's composable, type-safe
|
|
11
|
+
# predicate API — the same one ActiveRecord uses under the hood.
|
|
12
|
+
#
|
|
13
|
+
# @example Query running invocations for a service
|
|
14
|
+
# i = Restate::Sys::Invocation
|
|
15
|
+
# query = i.project(i[:id], i[:status], i[:created_at])
|
|
16
|
+
# .where(i[:target_service_name].eq("MyService"))
|
|
17
|
+
# .where(i[:status].eq("running"))
|
|
18
|
+
# .order(i[:created_at].desc)
|
|
19
|
+
# .take(50)
|
|
20
|
+
# Restate.query(query)
|
|
21
|
+
#
|
|
22
|
+
# @example Join invocations with their journal input
|
|
23
|
+
# i = Restate::Sys::Invocation
|
|
24
|
+
# j = Restate::Sys::Journal
|
|
25
|
+
# query = i.project(i[:id], i[:target], i[:status], j[:entry_json])
|
|
26
|
+
# .join(j, Arel::Nodes::OuterJoin)
|
|
27
|
+
# .on(j[:id].eq(i[:id]).and(j[:index].eq(0)))
|
|
28
|
+
# .where(i[:target_service_name].eq("CrawlPipeline"))
|
|
29
|
+
# .order(i[:created_at].desc)
|
|
30
|
+
# .take(20)
|
|
31
|
+
# Restate.query(query)
|
|
32
|
+
#
|
|
33
|
+
# @example Query virtual object state
|
|
34
|
+
# s = Restate::Sys::State
|
|
35
|
+
# query = s.project(s[:service_name], s[:service_key], s[:key], s[:value_utf8])
|
|
36
|
+
# .where(s[:service_name].eq("Counter"))
|
|
37
|
+
# Restate.query(query)
|
|
38
|
+
module Sys
|
|
39
|
+
Invocation = Arel::Table.new(:sys_invocation)
|
|
40
|
+
Journal = Arel::Table.new(:sys_journal)
|
|
41
|
+
JournalEvents = Arel::Table.new(:sys_journal_events)
|
|
42
|
+
Inbox = Arel::Table.new(:sys_inbox)
|
|
43
|
+
KeyedStatus = Arel::Table.new(:sys_keyed_service_status)
|
|
44
|
+
Service = Arel::Table.new(:sys_service)
|
|
45
|
+
Deployment = Arel::Table.new(:sys_deployment)
|
|
46
|
+
Idempotency = Arel::Table.new(:sys_idempotency)
|
|
47
|
+
Promise = Arel::Table.new(:sys_promise)
|
|
48
|
+
State = Arel::Table.new(:state)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Minimal quoting adapter for Arel's ToSql visitor. Emits ANSI SQL
|
|
52
|
+
# (double-quoted identifiers, single-quoted strings) which DataFusion expects.
|
|
53
|
+
# Allows Arel query generation without an ActiveRecord database connection.
|
|
54
|
+
#
|
|
55
|
+
# @!visibility private
|
|
56
|
+
class DataFusionQuoting
|
|
57
|
+
def quote_table_name(name)
|
|
58
|
+
"\"#{name}\""
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def quote_column_name(name)
|
|
62
|
+
"\"#{name}\""
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def quote(value)
|
|
66
|
+
case value
|
|
67
|
+
when String then "'#{value.gsub("'", "''")}'"
|
|
68
|
+
when nil then 'NULL'
|
|
69
|
+
when true then 'TRUE'
|
|
70
|
+
when false then 'FALSE'
|
|
71
|
+
else value.to_s
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def schema_cache
|
|
76
|
+
self
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def columns_hash(_table)
|
|
80
|
+
{}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def data_source_exists?(_table)
|
|
84
|
+
true
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Arel visitor that generates ANSI SQL compatible with DataFusion.
|
|
89
|
+
# Uses DataFusionQuoting for identifier/value quoting without requiring
|
|
90
|
+
# a live database connection.
|
|
91
|
+
#
|
|
92
|
+
# @!visibility private
|
|
93
|
+
class DataFusionVisitor < Arel::Visitors::ToSql
|
|
94
|
+
def initialize
|
|
95
|
+
super(DataFusionQuoting.new)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class << self
|
|
100
|
+
# Convert an Arel AST to a SQL string without requiring an AR connection.
|
|
101
|
+
# Uses a standalone visitor that emits ANSI SQL (DataFusion-compatible).
|
|
102
|
+
#
|
|
103
|
+
# @param arel [Arel::SelectManager] an Arel query
|
|
104
|
+
# @return [String] SQL string
|
|
105
|
+
def arel_to_sql(arel)
|
|
106
|
+
collector = Arel::Collectors::SQLString.new
|
|
107
|
+
DataFusionVisitor.new.accept(arel.ast, collector).value
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Execute an Arel query or raw SQL string against the Restate admin
|
|
111
|
+
# introspection API. Returns an array of row hashes.
|
|
112
|
+
#
|
|
113
|
+
# @param arel_or_sql [Arel::SelectManager, String] an Arel query or raw SQL
|
|
114
|
+
# @return [Array<Hash>] rows returned by Restate
|
|
115
|
+
#
|
|
116
|
+
# @example With Arel
|
|
117
|
+
# i = Restate::Sys::Invocation
|
|
118
|
+
# Restate.query(i.project(Arel.star).take(10))
|
|
119
|
+
#
|
|
120
|
+
# @example With raw SQL
|
|
121
|
+
# Restate.query("SELECT id, status FROM sys_invocation LIMIT 10")
|
|
122
|
+
def query(arel_or_sql)
|
|
123
|
+
sql = arel_or_sql.respond_to?(:ast) ? arel_to_sql(arel_or_sql) : arel_or_sql.to_s
|
|
124
|
+
client.execute_query(sql)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Restate
|
|
5
|
+
# Rails integration for the Restate SDK. Automatically loads the
|
|
6
|
+
# introspection module which provides Arel-based query support for
|
|
7
|
+
# Restate's SQL introspection API (powered by DataFusion).
|
|
8
|
+
#
|
|
9
|
+
# When Rails is present, +Restate::Sys+ table constants become available
|
|
10
|
+
# for building type-safe, composable queries against system tables like
|
|
11
|
+
# +sys_invocation+, +sys_journal+, and +state+.
|
|
12
|
+
class Railtie < Rails::Railtie
|
|
13
|
+
initializer 'restate.introspection' do
|
|
14
|
+
require_relative 'introspection'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/restate/server.rb
CHANGED
|
@@ -193,7 +193,8 @@ module Restate
|
|
|
193
193
|
invocation: invocation,
|
|
194
194
|
send_output: send_output,
|
|
195
195
|
input_queue: input_queue,
|
|
196
|
-
middleware: @endpoint.middleware
|
|
196
|
+
middleware: @endpoint.middleware,
|
|
197
|
+
outbound_middleware: @endpoint.outbound_middleware
|
|
197
198
|
)
|
|
198
199
|
|
|
199
200
|
# Spawn the handler as an async task so the response body can stream
|
|
@@ -23,7 +23,8 @@ module Restate
|
|
|
23
23
|
|
|
24
24
|
attr_reader :vm, :invocation
|
|
25
25
|
|
|
26
|
-
def initialize(vm:, handler:, invocation:, send_output:, input_queue:, middleware: []
|
|
26
|
+
def initialize(vm:, handler:, invocation:, send_output:, input_queue:, middleware: [],
|
|
27
|
+
outbound_middleware: [])
|
|
27
28
|
@vm = vm
|
|
28
29
|
@handler = handler
|
|
29
30
|
@invocation = invocation
|
|
@@ -32,6 +33,7 @@ module Restate
|
|
|
32
33
|
@run_coros_to_execute = {}
|
|
33
34
|
@attempt_finished_event = AttemptFinishedEvent.new
|
|
34
35
|
@middleware = middleware
|
|
36
|
+
@outbound_middleware = outbound_middleware
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
# ── Main entry point ──
|
|
@@ -204,12 +206,14 @@ module Restate
|
|
|
204
206
|
in_serde = resolve_serde(input_serde, handler_meta, :input_serde)
|
|
205
207
|
out_serde = resolve_serde(output_serde, handler_meta, :output_serde)
|
|
206
208
|
parameter = in_serde.serialize(arg)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
with_outbound_middleware(svc_name, handler_name, headers) do |hdrs|
|
|
210
|
+
call_handle = @vm.sys_call(
|
|
211
|
+
service: svc_name, handler: handler_name, parameter: parameter,
|
|
212
|
+
key: key, idempotency_key: idempotency_key, headers: hdrs
|
|
213
|
+
)
|
|
214
|
+
DurableCallFuture.new(self, call_handle.result_handle, call_handle.invocation_id_handle,
|
|
215
|
+
output_serde: out_serde)
|
|
216
|
+
end
|
|
213
217
|
end
|
|
214
218
|
|
|
215
219
|
# Sends a one-way invocation to a Restate service handler (fire-and-forget).
|
|
@@ -219,11 +223,13 @@ module Restate
|
|
|
219
223
|
in_serde = resolve_serde(input_serde, handler_meta, :input_serde)
|
|
220
224
|
parameter = in_serde.serialize(arg)
|
|
221
225
|
delay_ms = delay ? (delay * 1000).to_i : nil
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
with_outbound_middleware(svc_name, handler_name, headers) do |hdrs|
|
|
227
|
+
invocation_id_handle = @vm.sys_send(
|
|
228
|
+
service: svc_name, handler: handler_name, parameter: parameter,
|
|
229
|
+
key: key, delay: delay_ms, idempotency_key: idempotency_key, headers: hdrs
|
|
230
|
+
)
|
|
231
|
+
SendHandle.new(self, invocation_id_handle)
|
|
232
|
+
end
|
|
227
233
|
end
|
|
228
234
|
|
|
229
235
|
# Durably calls a handler on a Restate virtual object, keyed by +key+.
|
|
@@ -233,12 +239,14 @@ module Restate
|
|
|
233
239
|
in_serde = resolve_serde(input_serde, handler_meta, :input_serde)
|
|
234
240
|
out_serde = resolve_serde(output_serde, handler_meta, :output_serde)
|
|
235
241
|
parameter = in_serde.serialize(arg)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
+
with_outbound_middleware(svc_name, handler_name, headers) do |hdrs|
|
|
243
|
+
call_handle = @vm.sys_call(
|
|
244
|
+
service: svc_name, handler: handler_name, parameter: parameter,
|
|
245
|
+
key: key, idempotency_key: idempotency_key, headers: hdrs
|
|
246
|
+
)
|
|
247
|
+
DurableCallFuture.new(self, call_handle.result_handle, call_handle.invocation_id_handle,
|
|
248
|
+
output_serde: out_serde)
|
|
249
|
+
end
|
|
242
250
|
end
|
|
243
251
|
|
|
244
252
|
# Sends a one-way invocation to a Restate virtual object handler (fire-and-forget).
|
|
@@ -248,11 +256,13 @@ module Restate
|
|
|
248
256
|
in_serde = resolve_serde(input_serde, handler_meta, :input_serde)
|
|
249
257
|
parameter = in_serde.serialize(arg)
|
|
250
258
|
delay_ms = delay ? (delay * 1000).to_i : nil
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
259
|
+
with_outbound_middleware(svc_name, handler_name, headers) do |hdrs|
|
|
260
|
+
invocation_id_handle = @vm.sys_send(
|
|
261
|
+
service: svc_name, handler: handler_name, parameter: parameter,
|
|
262
|
+
key: key, delay: delay_ms, idempotency_key: idempotency_key, headers: hdrs
|
|
263
|
+
)
|
|
264
|
+
SendHandle.new(self, invocation_id_handle)
|
|
265
|
+
end
|
|
256
266
|
end
|
|
257
267
|
|
|
258
268
|
# Durably calls a handler on a Restate workflow, keyed by +key+.
|
|
@@ -332,22 +342,26 @@ module Restate
|
|
|
332
342
|
|
|
333
343
|
# Durably calls a handler using raw bytes (no serialization). Useful for proxying.
|
|
334
344
|
def generic_call(service, handler, arg, key: nil, idempotency_key: nil, headers: nil)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
345
|
+
with_outbound_middleware(service, handler, headers) do |hdrs|
|
|
346
|
+
call_handle = @vm.sys_call(
|
|
347
|
+
service: service, handler: handler, parameter: arg,
|
|
348
|
+
key: key, idempotency_key: idempotency_key, headers: hdrs
|
|
349
|
+
)
|
|
350
|
+
DurableCallFuture.new(self, call_handle.result_handle, call_handle.invocation_id_handle,
|
|
351
|
+
output_serde: nil)
|
|
352
|
+
end
|
|
341
353
|
end
|
|
342
354
|
|
|
343
355
|
# Sends a one-way invocation using raw bytes (no serialization). Useful for proxying.
|
|
344
356
|
def generic_send(service, handler, arg, key: nil, delay: nil, idempotency_key: nil, headers: nil)
|
|
345
357
|
delay_ms = delay ? (delay * 1000).to_i : nil
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
358
|
+
with_outbound_middleware(service, handler, headers) do |hdrs|
|
|
359
|
+
invocation_id_handle = @vm.sys_send(
|
|
360
|
+
service: service, handler: handler, parameter: arg,
|
|
361
|
+
key: key, delay: delay_ms, idempotency_key: idempotency_key, headers: hdrs
|
|
362
|
+
)
|
|
363
|
+
SendHandle.new(self, invocation_id_handle)
|
|
364
|
+
end
|
|
351
365
|
end
|
|
352
366
|
|
|
353
367
|
# ── Request metadata ──
|
|
@@ -453,6 +467,25 @@ module Restate
|
|
|
453
467
|
end
|
|
454
468
|
end
|
|
455
469
|
|
|
470
|
+
# ── Outbound middleware ──
|
|
471
|
+
|
|
472
|
+
# Runs outbound middleware chain (Sidekiq client middleware pattern).
|
|
473
|
+
# Each middleware gets +call(service, handler, headers)+ and must +yield+
|
|
474
|
+
# to continue the chain. The block at the end performs the actual VM call.
|
|
475
|
+
def with_outbound_middleware(service, handler, headers, &action)
|
|
476
|
+
if @outbound_middleware.empty?
|
|
477
|
+
action.call(headers)
|
|
478
|
+
else
|
|
479
|
+
h = headers || {}
|
|
480
|
+
chain = ->(hdrs) { action.call(hdrs) }
|
|
481
|
+
@outbound_middleware.reverse_each do |mw|
|
|
482
|
+
prev = chain
|
|
483
|
+
chain = ->(hdrs) { mw.call(service, handler, hdrs) { prev.call(hdrs) } }
|
|
484
|
+
end
|
|
485
|
+
chain.call(h)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
456
489
|
# ── Call target resolution ──
|
|
457
490
|
|
|
458
491
|
# Resolves a service+handler pair from class/symbol or string/string.
|
data/lib/restate/version.rb
CHANGED
data/lib/restate.rb
CHANGED
|
@@ -18,6 +18,7 @@ require_relative 'restate/endpoint'
|
|
|
18
18
|
require_relative 'restate/service_proxy'
|
|
19
19
|
require_relative 'restate/config'
|
|
20
20
|
require_relative 'restate/client'
|
|
21
|
+
require_relative 'restate/railtie' if defined?(Rails::Railtie)
|
|
21
22
|
|
|
22
23
|
# Restate Ruby SDK — build resilient applications with durable execution.
|
|
23
24
|
#
|
data/sig/restate.rbs
CHANGED
|
@@ -8,6 +8,8 @@ module Restate
|
|
|
8
8
|
def self.configure: () { (Config) -> void } -> void
|
|
9
9
|
def self.config: () -> Config
|
|
10
10
|
def self.client: () -> Client
|
|
11
|
+
def self.query: (untyped arel_or_sql) -> Array[Hash[String, untyped]]
|
|
12
|
+
def self.arel_to_sql: (untyped arel) -> String
|
|
11
13
|
|
|
12
14
|
# ── Durable execution ──
|
|
13
15
|
|
|
@@ -118,6 +120,7 @@ module Restate
|
|
|
118
120
|
def reject_awakeable: (String awakeable_id, String message, ?code: Integer) -> void
|
|
119
121
|
def cancel_invocation: (String invocation_id) -> void
|
|
120
122
|
def kill_invocation: (String invocation_id) -> void
|
|
123
|
+
def execute_query: (String sql) -> Array[Hash[String, untyped]]
|
|
121
124
|
|
|
122
125
|
private
|
|
123
126
|
|
|
@@ -138,13 +141,19 @@ module Restate
|
|
|
138
141
|
attr_reader identity_keys: Array[String]
|
|
139
142
|
attr_accessor protocol: String?
|
|
140
143
|
attr_reader middleware: Array[untyped]
|
|
144
|
+
attr_reader outbound_middleware: Array[untyped]
|
|
141
145
|
def initialize: () -> void
|
|
142
146
|
def bind: (*untyped svcs) -> self
|
|
143
147
|
def streaming_protocol: () -> self
|
|
144
148
|
def request_response_protocol: () -> self
|
|
145
149
|
def identity_key: (String key) -> self
|
|
146
150
|
def use: (untyped klass, *untyped args, **untyped kwargs) -> self
|
|
151
|
+
def use_outbound: (untyped klass, *untyped args, **untyped kwargs) -> self
|
|
147
152
|
def app: () -> untyped
|
|
153
|
+
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
def instantiate_middleware: (untyped klass, Array[untyped] args, Hash[Symbol, untyped] kwargs) -> untyped
|
|
148
157
|
end
|
|
149
158
|
|
|
150
159
|
# ── Service proxies ──
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: restate-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Restate Developers
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: async
|
|
@@ -54,7 +54,6 @@ files:
|
|
|
54
54
|
- ext/restate_internal/extconf.rb
|
|
55
55
|
- ext/restate_internal/src/lib.rs
|
|
56
56
|
- lib/restate.rb
|
|
57
|
-
- lib/restate/3.2/restate_internal.so
|
|
58
57
|
- lib/restate/3.3/restate_internal.so
|
|
59
58
|
- lib/restate/3.4/restate_internal.so
|
|
60
59
|
- lib/restate/4.0/restate_internal.so
|
|
@@ -66,6 +65,8 @@ files:
|
|
|
66
65
|
- lib/restate/endpoint.rb
|
|
67
66
|
- lib/restate/errors.rb
|
|
68
67
|
- lib/restate/handler.rb
|
|
68
|
+
- lib/restate/introspection.rb
|
|
69
|
+
- lib/restate/railtie.rb
|
|
69
70
|
- lib/restate/serde.rb
|
|
70
71
|
- lib/restate/server.rb
|
|
71
72
|
- lib/restate/server_context.rb
|
|
@@ -91,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
91
92
|
requirements:
|
|
92
93
|
- - ">="
|
|
93
94
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: '3.
|
|
95
|
+
version: '3.3'
|
|
95
96
|
- - "<"
|
|
96
97
|
- !ruby/object:Gem::Version
|
|
97
98
|
version: 4.1.dev
|
|
Binary file
|