solid_objects 0.14.6 → 0.14.7
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/CHANGELOG.md +9 -0
- data/Rakefile +1 -1
- data/docs/architecture.md +48 -0
- data/docs/development.md +110 -0
- data/docs/operations.md +6 -0
- data/docs/reminders.md +8 -0
- data/docs/roadmap.md +6 -0
- data/lib/solid_objects/actor_signatures.rb +80 -0
- data/lib/solid_objects/effect_executor.rb +11 -15
- data/lib/solid_objects/effect_payload.rb +27 -0
- data/lib/solid_objects/version.rb +1 -1
- data/lib/solid_objects.rb +1 -0
- data/sig/generated/lib/solid_objects/actor_signatures.rbs +24 -0
- data/sig/generated/lib/solid_objects/effect_payload.rbs +14 -0
- data/sig/public/effect_payload.rbs +19 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d36e77947a8de94216c9174cc3a34a878803bdf242efa0b10f6067d48b4e7cda
|
|
4
|
+
data.tar.gz: 178955e77093552df5569ee5c0badfb6035a51a479c7bcfbd1025465ac5947a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 491698862debab8266650dbdc21a86561d3fa7dd51764edd469a7b5173a1b2a24a2542d39a584796d3433a2bc66794d7d5251ebfe73d7c991d539f2a4c92d287
|
|
7
|
+
data.tar.gz: 705ce841595e49cbc892535afd15fb96b8ac4134bb01a1c92de8d12061a6fe5717b745d989decf82fb1c25a19966b9e50a88afb30a1426c23055e1333c00f2cc
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.14.7 - 2026-09-14
|
|
4
|
+
|
|
5
|
+
- Publish RBS contracts for effect callback envelopes and Ruby error summaries.
|
|
6
|
+
Check the runtime constructors and packaged consumer signatures strictly,
|
|
7
|
+
preserving ordinary hashes, keyword callbacks, serialization, and retries.
|
|
8
|
+
- Add optional actor-specific RBS generation for staged schedule/transmit calls
|
|
9
|
+
and effect callback names. Reuse application-declared operation argument types
|
|
10
|
+
without changing Ruby dispatch, runtime validation, or global effect registries.
|
|
11
|
+
|
|
3
12
|
## 0.14.6 - 2026-09-12
|
|
4
13
|
|
|
5
14
|
- Preserve committed turns when an Active Record after-commit callback raises.
|
data/Rakefile
CHANGED
|
@@ -14,7 +14,7 @@ task :rbs do
|
|
|
14
14
|
FileUtils.rm_rf(File.expand_path("sig/generated", __dir__))
|
|
15
15
|
sh "bundle exec rbs-inline --base lib --base app --output sig/generated lib app"
|
|
16
16
|
FileUtils.rm_f(File.expand_path("sig/generated/lib/generators/solid_objects/templates/solid_objects.rbs", __dir__))
|
|
17
|
-
sh "bundle exec rbs -I sig/generated -I sig/support validate"
|
|
17
|
+
sh "bundle exec rbs -I sig/generated -I sig/support -I sig/public validate"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
desc "Run Standard Ruby"
|
data/docs/architecture.md
CHANGED
|
@@ -443,6 +443,10 @@ a dead letter.
|
|
|
443
443
|
|
|
444
444
|
`emit` creates a staged effect:
|
|
445
445
|
|
|
446
|
+
Typed applications can generate [actor-specific RBS signatures](development.md#actor-specific-dispatch-signatures)
|
|
447
|
+
to check callback names and staged `schedule`/`transmit` calls without changing
|
|
448
|
+
their Ruby syntax. Effect and commit-action registry names remain independent.
|
|
449
|
+
|
|
446
450
|
```ruby
|
|
447
451
|
emit(
|
|
448
452
|
:charge_payment,
|
|
@@ -483,6 +487,50 @@ and `result:`. A failure callback receives `effect_id:`, `arguments:`, and
|
|
|
483
487
|
`error:`, so an actor can correlate concurrent effects without storing a
|
|
484
488
|
separate callback ledger.
|
|
485
489
|
|
|
490
|
+
### Typing your on_failure handler
|
|
491
|
+
|
|
492
|
+
The gem ships `SolidObjects::effect_error`,
|
|
493
|
+
`SolidObjects::effect_failure_payload[Arguments]`, and
|
|
494
|
+
`SolidObjects::effect_success_payload[Arguments, Result]` as public RBS aliases.
|
|
495
|
+
They describe the existing string-keyed hashes; they are not Ruby wrapper classes.
|
|
496
|
+
See [signature loading](development.md#public-effect-payload-signatures) for Steep setup.
|
|
497
|
+
|
|
498
|
+
For an actor with `generation` and `status` attributes, declare the callback keywords
|
|
499
|
+
in the application's RBS:
|
|
500
|
+
|
|
501
|
+
```rbs
|
|
502
|
+
class ChatRun < SolidObjects::Actor
|
|
503
|
+
type run_arguments = { "generation" => Integer }
|
|
504
|
+
def fail_turn: (effect_id: String, arguments: run_arguments, error: SolidObjects::effect_error) -> void
|
|
505
|
+
end
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
```ruby
|
|
509
|
+
def fail_turn(effect_id:, arguments:, error:)
|
|
510
|
+
return unless arguments["generation"] == generation
|
|
511
|
+
|
|
512
|
+
self.status = "failed"
|
|
513
|
+
end
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Record access with `arguments["generation"]` retains its declared `Integer` type.
|
|
517
|
+
The callback receives top-level keywords, while nested arguments and error keys
|
|
518
|
+
remain strings. The failure envelope requires `"effect_id"`, `"arguments"`, and
|
|
519
|
+
`"error"`; the success envelope replaces `"error"` with `"result"`. Empty original
|
|
520
|
+
arguments remain `{}`, and a success result may be `nil` or any supported JSON value.
|
|
521
|
+
Ruby errors contain `"class"` (`String?`, including anonymous exception classes),
|
|
522
|
+
`"message"` (`String`, limited to 8,192 bytes), and `"backtrace"` (`Array[String]`,
|
|
523
|
+
limited to 50 entries and possibly empty).
|
|
524
|
+
|
|
525
|
+
Applications supply the generic argument/result types to describe their serialized
|
|
526
|
+
JSON values. These aliases do not infer or validate independently registered effect
|
|
527
|
+
handlers. Their type parameters are deliberately unconstrained: Ruby serialization
|
|
528
|
+
accepts and normalizes values such as symbols, and RBS cannot express that conversion
|
|
529
|
+
as a generic bound. The constructors and consumer fixtures are checked with strict
|
|
530
|
+
Steep diagnostics. JavaScript exposes equivalent contracts with its existing
|
|
531
|
+
camelCase ID and `{ name, message }` error shape in
|
|
532
|
+
[solid-objects-js#47](https://github.com/cardmagic/solid-objects-js/issues/47).
|
|
533
|
+
|
|
486
534
|
A commit action is registered the same way and runs inside the short fenced
|
|
487
535
|
transaction:
|
|
488
536
|
|
data/docs/development.md
CHANGED
|
@@ -103,6 +103,116 @@ bundle exec rake rbs
|
|
|
103
103
|
|
|
104
104
|
This follows the inline convention used by `cardmagic/classifier`.
|
|
105
105
|
|
|
106
|
+
### Public effect payload signatures
|
|
107
|
+
|
|
108
|
+
The packaged `sig/public` directory owns the reusable effect payload aliases and
|
|
109
|
+
survives `rake rbs` regeneration. A host application's Steep target can load the
|
|
110
|
+
installed gem's complete signature tree alongside its own signatures:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
target :app do
|
|
114
|
+
library "solid_objects"
|
|
115
|
+
signature "sig"
|
|
116
|
+
check "app/actors"
|
|
117
|
+
configure_code_diagnostics(Diagnostic::Ruby.strict)
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This requires no internal runtime imports. See the
|
|
122
|
+
[typed callback example](architecture.md#typing-your-on_failure-handler).
|
|
123
|
+
The gem's strict payload target checks the actual constructors; its packaged
|
|
124
|
+
consumer test also verifies that missing keys and incorrect field types fail.
|
|
125
|
+
|
|
126
|
+
### Actor-specific dispatch signatures
|
|
127
|
+
|
|
128
|
+
Typed applications can opt into `SolidObjects::ActorSignatures` to check ordinary
|
|
129
|
+
`schedule`, `transmit`, and effect callback names inside actor methods. Add `rbs`
|
|
130
|
+
and `steep` to the application's development dependencies. This tool is loaded
|
|
131
|
+
explicitly and is not required by workers or ordinary Ruby applications.
|
|
132
|
+
|
|
133
|
+
Declare application operation types first, including inherited operations and
|
|
134
|
+
block-defined `message` operations. Inline RBS can generate this input, or keep
|
|
135
|
+
handwritten declarations in a separate directory such as `sig/actors`:
|
|
136
|
+
|
|
137
|
+
```rbs
|
|
138
|
+
class ChatRun < SolidObjects::Actor
|
|
139
|
+
def recover_if_stuck: (generation: Integer) -> nil
|
|
140
|
+
def fail_turn: (effect_id: String, arguments: Hash[String, untyped], error: Hash[String, untyped]) -> nil
|
|
141
|
+
def start: () -> nil
|
|
142
|
+
end
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
After loading the application's actor classes, generate a separate output file:
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
require "solid_objects/actor_signatures"
|
|
149
|
+
|
|
150
|
+
Rails.application.reloader.wrap do
|
|
151
|
+
signatures = SolidObjects::ActorSignatures.generate(
|
|
152
|
+
actors: [ChatRun],
|
|
153
|
+
signatures: [Rails.root.join("sig/actors").to_s]
|
|
154
|
+
)
|
|
155
|
+
FileUtils.mkdir_p(Rails.root.join("sig/generated"))
|
|
156
|
+
File.write(Rails.root.join("sig/generated/solid_objects.rbs"), signatures)
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Run that script with `bin/rails runner` during development or CI. Outside Rails,
|
|
161
|
+
require the actor definitions and call `generate` directly. The generator returns
|
|
162
|
+
a string and does not write files, execute actor operations, start workers, or run
|
|
163
|
+
migrations. Rails boot follows the application's normal loading configuration;
|
|
164
|
+
the explicit actor list resolves its autoloaded classes within the reloader boundary.
|
|
165
|
+
Keep generated output out of the input signature paths, and regenerate after a
|
|
166
|
+
message is renamed or removed. Output is deterministic; handwritten signatures
|
|
167
|
+
remain separate.
|
|
168
|
+
|
|
169
|
+
Load the gem and both application signature directories in `Steepfile`:
|
|
170
|
+
|
|
171
|
+
```ruby
|
|
172
|
+
target :actors do
|
|
173
|
+
library "solid_objects"
|
|
174
|
+
signature "sig/actors"
|
|
175
|
+
signature "sig/generated"
|
|
176
|
+
check "app/actors"
|
|
177
|
+
configure_code_diagnostics(Diagnostic::Ruby.strict)
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The usual Ruby code now passes Steep without a dispatcher cast:
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
schedule(at: Time.now, key: "watchdog").recover_if_stuck(generation: 1)
|
|
185
|
+
transmit.recover_if_stuck(generation: 1)
|
|
186
|
+
emit :run_model, generation: 1, on_failure: :fail_turn
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Misspelled operations/callbacks, queries, attributes, private methods, infrastructure
|
|
190
|
+
methods, and incorrect keyword arguments fail the strict check. Both string and
|
|
191
|
+
symbol callback literals work. Staging returns `nil` even when an operation's own
|
|
192
|
+
return type differs. Effect and commit-action names remain global registry names;
|
|
193
|
+
registry contract inference is separate work.
|
|
194
|
+
|
|
195
|
+
Reflection supplies message names only. Values come from declared RBS signatures;
|
|
196
|
+
missing signatures and positional/block arguments are rejected. Block-defined
|
|
197
|
+
messages require explicit method declarations in RBS; annotate their block-local
|
|
198
|
+
values separately when checking the block body. Generic actor classes currently
|
|
199
|
+
require application-owned dispatcher signatures. The generator preserves method
|
|
200
|
+
overloads and method type parameters.
|
|
201
|
+
|
|
202
|
+
Deliberately dynamic names can use Ruby's explicit dynamic dispatch:
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
schedule(at: Time.now).public_send(operation_name, generation: generation)
|
|
206
|
+
public_send(:emit, :run_model, on_failure: callback_name, generation: generation)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Those calls opt out of name/argument checking and retain the existing runtime
|
|
210
|
+
validation. Ordinary calls on the generated dispatcher have no string-name fallback.
|
|
211
|
+
`send_to`, `Reference#async`, direct calls, and queries retain their existing
|
|
212
|
+
signatures and runtime behavior; this generator does not provide complete reference
|
|
213
|
+
typing or Sorbet/Tapioca actor-specific RBI generation. The corresponding TypeScript
|
|
214
|
+
work is tracked in [solid-objects-js#46](https://github.com/cardmagic/solid-objects-js/issues/46).
|
|
215
|
+
|
|
106
216
|
## Formatting and security
|
|
107
217
|
|
|
108
218
|
```bash
|
data/docs/operations.md
CHANGED
|
@@ -69,6 +69,12 @@ Rails schema migrations and actor state migrations are separate concerns.
|
|
|
69
69
|
|
|
70
70
|
### Host application tooling
|
|
71
71
|
|
|
72
|
+
RBS/Steep applications can generate
|
|
73
|
+
[actor-specific dispatch signatures](development.md#actor-specific-dispatch-signatures)
|
|
74
|
+
for reminders, transmit calls, and effect callback names. This is optional development
|
|
75
|
+
tooling; generated signatures do not change runtime dispatch. The generator does
|
|
76
|
+
not supply equivalent Sorbet/Tapioca actor-specific types.
|
|
77
|
+
|
|
72
78
|
Installed engine migrations are copied as
|
|
73
79
|
`db/migrate/*_create_solid_objects_tables.solid_objects.rb`. If the host enables
|
|
74
80
|
`Rails/CreateTableWithTimestamps`, exclude engine-owned migrations rather than
|
data/docs/reminders.md
CHANGED
|
@@ -39,6 +39,14 @@ raises, and nothing is logged except a `solid_objects.reminder.replaced` event.
|
|
|
39
39
|
|
|
40
40
|
## An alarm per item, with `key:`
|
|
41
41
|
|
|
42
|
+
For watchdogs paired with an effect's give-up callback, see
|
|
43
|
+
[typing your `on_failure` handler](architecture.md#typing-your-on_failure-handler)
|
|
44
|
+
to retain the original argument types without repeating the error hash contract.
|
|
45
|
+
|
|
46
|
+
For static checking of watchdog operation names and keyword arguments, opt into
|
|
47
|
+
[actor-specific RBS signatures](development.md#actor-specific-dispatch-signatures).
|
|
48
|
+
The Ruby `schedule(...).recover_if_stuck(generation: ...)` syntax stays the same.
|
|
49
|
+
|
|
42
50
|
Pass `key:` when an actor is waiting on several things at once. The key is your
|
|
43
51
|
own identifier for the item, and it names that item's alarm, so each item gets
|
|
44
52
|
one:
|
data/docs/roadmap.md
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
dead letters, and tail retry
|
|
15
15
|
- Transactional effects with success/failure actor messages carrying the
|
|
16
16
|
originally staged arguments for callback correlation
|
|
17
|
+
- Public RBS effect success/failure envelopes and error records, checked against
|
|
18
|
+
the runtime constructors and a packaged consumer with strict Steep diagnostics
|
|
17
19
|
- Actor-to-actor asynchronous outbox delivery. Effects and broadcasts use
|
|
18
20
|
portable status rows with polling indexes and database check constraints on
|
|
19
21
|
status, which works on all three adapters; a future version may add narrow
|
|
@@ -65,6 +67,10 @@
|
|
|
65
67
|
gem's dependencies
|
|
66
68
|
- Inline RBS generation/validation, Steep, Standard Ruby, Solid Queue's exact
|
|
67
69
|
RuboCop policy, and a warning-free Brakeman scan
|
|
70
|
+
- Opt-in actor-specific RBS generation for schedule/transmit keyword arguments
|
|
71
|
+
and effect callback names, using application declarations and checked consumer
|
|
72
|
+
fixtures. Dynamic names remain an explicit escape hatch; complete reference
|
|
73
|
+
typing and actor-specific RBI generation are separate work
|
|
68
74
|
- Compatibility CI across the supported span: Ruby 3.3, 3.4, and 4.0 against
|
|
69
75
|
Rails 7.1, 7.2, 8.0, and 8.1, pinned through `RAILS_VERSION` so the advertised
|
|
70
76
|
range is verified rather than assumed. The compatibility job runs SQLite only;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
|
|
3
|
+
require "solid_objects"
|
|
4
|
+
require "rbs"
|
|
5
|
+
require "pathname"
|
|
6
|
+
|
|
7
|
+
module SolidObjects
|
|
8
|
+
class ActorSignatures
|
|
9
|
+
# @rbs (actors: Array[Class], signatures: Array[String]) -> String
|
|
10
|
+
def self.generate(actors:, signatures:)
|
|
11
|
+
new(signatures:).generate(actors:)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @rbs @builder: untyped
|
|
15
|
+
|
|
16
|
+
# @rbs (signatures: Array[String]) -> void
|
|
17
|
+
def initialize(signatures:)
|
|
18
|
+
loader = RBS::EnvironmentLoader.new
|
|
19
|
+
loader.add(path: Pathname.new(File.expand_path("../../sig", __dir__)))
|
|
20
|
+
signatures.sort.each { |path| loader.add(path: Pathname.new(path)) }
|
|
21
|
+
environment = RBS::Environment.from_loader(loader).resolve_type_names
|
|
22
|
+
@builder = RBS::DefinitionBuilder.new(env: environment)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @rbs (actors: Array[Class]) -> String
|
|
26
|
+
def generate(actors:)
|
|
27
|
+
actors.uniq.sort_by { |actor| actor.name.to_s }.map { |actor| actor_signature(actor) }.join("\n")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# @rbs (untyped) -> String
|
|
33
|
+
def actor_signature(actor)
|
|
34
|
+
unless actor < Actor && actor.name
|
|
35
|
+
raise ArgumentError, "actor signatures require named SolidObjects::Actor subclasses"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
name = RBS::TypeName.parse("::#{actor.name}")
|
|
39
|
+
definition = @builder.build_instance(name)
|
|
40
|
+
if definition.type_params.any?
|
|
41
|
+
raise ArgumentError, "generic actor classes require application-owned dispatcher signatures"
|
|
42
|
+
end
|
|
43
|
+
messages = actor.definition.messages.keys.sort
|
|
44
|
+
methods = messages.map do |operation|
|
|
45
|
+
method = definition.methods[operation]
|
|
46
|
+
unless method && method.accessibility == :public
|
|
47
|
+
raise ArgumentError, "declare a public RBS signature for #{actor.name}##{operation}"
|
|
48
|
+
end
|
|
49
|
+
types = method.method_types.map { |type| staged_type(type, actor.name, operation).to_s }
|
|
50
|
+
" def #{operation}: #{types.join("\n | ")}"
|
|
51
|
+
end
|
|
52
|
+
callback_names = messages.flat_map { |operation| [ operation.inspect, operation.to_s.inspect ] }
|
|
53
|
+
callbacks = (callback_names + [ "nil" ]).join(" | ")
|
|
54
|
+
<<~RBS
|
|
55
|
+
class #{name}
|
|
56
|
+
interface _SolidObjectsOperations
|
|
57
|
+
#{methods.join("\n")}
|
|
58
|
+
def public_send: (Symbol | String, **untyped) -> nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def schedule: (at: Time, ?every: Numeric?, ?missed: Symbol | String, ?key: (String | Symbol | Integer)?) -> #{name}::_SolidObjectsOperations
|
|
62
|
+
def transmit: () -> #{name}::_SolidObjectsOperations
|
|
63
|
+
def emit: (Symbol | String, ?on_success: (#{callbacks}), ?on_failure: (#{callbacks}), **untyped) -> nil
|
|
64
|
+
end
|
|
65
|
+
RBS
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @rbs (untyped, String, Symbol) -> untyped
|
|
69
|
+
def staged_type(method_type, actor_name, operation)
|
|
70
|
+
function = method_type.type
|
|
71
|
+
if !function.is_a?(RBS::Types::Function) || method_type.block ||
|
|
72
|
+
function.required_positionals.any? || function.optional_positionals.any? ||
|
|
73
|
+
function.rest_positionals || function.trailing_positionals.any?
|
|
74
|
+
raise ArgumentError, "#{actor_name}##{operation} must declare keyword-only arguments without a block"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
method_type.update(type: function.update(return_type: RBS::Types::Bases::Nil.new(location: nil)))
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -184,11 +184,11 @@ module SolidObjects
|
|
|
184
184
|
effect: locked_effect,
|
|
185
185
|
operation: locked_effect.success_operation,
|
|
186
186
|
outcome: "success",
|
|
187
|
-
arguments:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
arguments: EffectPayload.success(
|
|
188
|
+
effect_id: locked_effect.effect_id,
|
|
189
|
+
arguments: locked_effect.arguments,
|
|
190
|
+
result: serialized_result
|
|
191
|
+
)
|
|
192
192
|
)
|
|
193
193
|
locked_effect.update!(
|
|
194
194
|
status: "completed",
|
|
@@ -216,21 +216,17 @@ module SolidObjects
|
|
|
216
216
|
locked_effect = Effect.lock.find(effect.id)
|
|
217
217
|
verify_claim!(locked_effect)
|
|
218
218
|
dead = locked_effect.attempt_count >= locked_effect.max_attempts
|
|
219
|
-
error_details =
|
|
220
|
-
"class" => error.class.name,
|
|
221
|
-
"message" => error.message.to_s.byteslice(0, 8_192),
|
|
222
|
-
"backtrace" => Array(error.backtrace).first(50)
|
|
223
|
-
}
|
|
219
|
+
error_details = EffectPayload.error(error)
|
|
224
220
|
if dead
|
|
225
221
|
result_message = enqueue_result_message(
|
|
226
222
|
effect: locked_effect,
|
|
227
223
|
operation: locked_effect.failure_operation,
|
|
228
224
|
outcome: "failure",
|
|
229
|
-
arguments:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
225
|
+
arguments: EffectPayload.failure(
|
|
226
|
+
effect_id: locked_effect.effect_id,
|
|
227
|
+
arguments: locked_effect.arguments,
|
|
228
|
+
error: error_details
|
|
229
|
+
)
|
|
234
230
|
)
|
|
235
231
|
end
|
|
236
232
|
locked_effect.update!(
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
|
|
3
|
+
module SolidObjects
|
|
4
|
+
module EffectPayload
|
|
5
|
+
class << self
|
|
6
|
+
# @rbs [Arguments, Result] (effect_id: String, arguments: Arguments, result: Result) -> effect_success_payload[Arguments, Result]
|
|
7
|
+
def success(effect_id:, arguments:, result:)
|
|
8
|
+
{ "effect_id" => effect_id, "arguments" => arguments, "result" => result }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @rbs [Arguments] (effect_id: String, arguments: Arguments, error: effect_error) -> effect_failure_payload[Arguments]
|
|
12
|
+
def failure(effect_id:, arguments:, error:)
|
|
13
|
+
{ "effect_id" => effect_id, "arguments" => arguments, "error" => error }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs (Exception) -> effect_error
|
|
17
|
+
def error(exception)
|
|
18
|
+
message = exception.message.to_s.byteslice(0, 8_192) # : String
|
|
19
|
+
{
|
|
20
|
+
"class" => exception.class.name,
|
|
21
|
+
"message" => message,
|
|
22
|
+
"backtrace" => Array(exception.backtrace).first(50)
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/solid_objects.rb
CHANGED
|
@@ -55,6 +55,7 @@ require "solid_objects/wake_up_adapters/redis"
|
|
|
55
55
|
require "solid_objects/wake_up_adapters"
|
|
56
56
|
require "solid_objects/polling_backoff"
|
|
57
57
|
require "solid_objects/effect_registry"
|
|
58
|
+
require "solid_objects/effect_payload"
|
|
58
59
|
require "solid_objects/commit_action_registry"
|
|
59
60
|
require "solid_objects/lease"
|
|
60
61
|
require "solid_objects/lease_renewer"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated from lib/solid_objects/actor_signatures.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module SolidObjects
|
|
4
|
+
class ActorSignatures
|
|
5
|
+
# @rbs (actors: Array[Class], signatures: Array[String]) -> String
|
|
6
|
+
def self.generate: (actors: Array[Class], signatures: Array[String]) -> String
|
|
7
|
+
|
|
8
|
+
@builder: untyped
|
|
9
|
+
|
|
10
|
+
# @rbs (signatures: Array[String]) -> void
|
|
11
|
+
def initialize: (signatures: Array[String]) -> void
|
|
12
|
+
|
|
13
|
+
# @rbs (actors: Array[Class]) -> String
|
|
14
|
+
def generate: (actors: Array[Class]) -> String
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# @rbs (untyped) -> String
|
|
19
|
+
def actor_signature: (untyped) -> String
|
|
20
|
+
|
|
21
|
+
# @rbs (untyped, String, Symbol) -> untyped
|
|
22
|
+
def staged_type: (untyped, String, Symbol) -> untyped
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Generated from lib/solid_objects/effect_payload.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module SolidObjects
|
|
4
|
+
module EffectPayload
|
|
5
|
+
# @rbs [Arguments, Result] (effect_id: String, arguments: Arguments, result: Result) -> effect_success_payload[Arguments, Result]
|
|
6
|
+
def self.success: [Arguments, Result] (effect_id: String, arguments: Arguments, result: Result) -> effect_success_payload[Arguments, Result]
|
|
7
|
+
|
|
8
|
+
# @rbs [Arguments] (effect_id: String, arguments: Arguments, error: effect_error) -> effect_failure_payload[Arguments]
|
|
9
|
+
def self.failure: [Arguments] (effect_id: String, arguments: Arguments, error: effect_error) -> effect_failure_payload[Arguments]
|
|
10
|
+
|
|
11
|
+
# @rbs (Exception) -> effect_error
|
|
12
|
+
def self.error: (Exception) -> effect_error
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module SolidObjects
|
|
2
|
+
type effect_error = {
|
|
3
|
+
"class" => String?,
|
|
4
|
+
"message" => String,
|
|
5
|
+
"backtrace" => Array[String]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type effect_failure_payload[Arguments] = {
|
|
9
|
+
"effect_id" => String,
|
|
10
|
+
"arguments" => Arguments,
|
|
11
|
+
"error" => effect_error
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type effect_success_payload[Arguments, Result] = {
|
|
15
|
+
"effect_id" => String,
|
|
16
|
+
"arguments" => Arguments,
|
|
17
|
+
"result" => Result
|
|
18
|
+
}
|
|
19
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solid_objects
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.14.
|
|
4
|
+
version: 0.14.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lucas Carlson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: actioncable
|
|
@@ -389,6 +389,7 @@ files:
|
|
|
389
389
|
- lib/solid_objects/actor_channel.rb
|
|
390
390
|
- lib/solid_objects/actor_definition.rb
|
|
391
391
|
- lib/solid_objects/actor_registry.rb
|
|
392
|
+
- lib/solid_objects/actor_signatures.rb
|
|
392
393
|
- lib/solid_objects/actor_snapshot.rb
|
|
393
394
|
- lib/solid_objects/actor_view.rb
|
|
394
395
|
- lib/solid_objects/administration.rb
|
|
@@ -416,6 +417,7 @@ files:
|
|
|
416
417
|
- lib/solid_objects/doctor.rb
|
|
417
418
|
- lib/solid_objects/dom_identity.rb
|
|
418
419
|
- lib/solid_objects/effect_executor.rb
|
|
420
|
+
- lib/solid_objects/effect_payload.rb
|
|
419
421
|
- lib/solid_objects/effect_registry.rb
|
|
420
422
|
- lib/solid_objects/engine.rb
|
|
421
423
|
- lib/solid_objects/errors.rb
|
|
@@ -478,6 +480,7 @@ files:
|
|
|
478
480
|
- sig/generated/lib/solid_objects/actor_channel.rbs
|
|
479
481
|
- sig/generated/lib/solid_objects/actor_definition.rbs
|
|
480
482
|
- sig/generated/lib/solid_objects/actor_registry.rbs
|
|
483
|
+
- sig/generated/lib/solid_objects/actor_signatures.rbs
|
|
481
484
|
- sig/generated/lib/solid_objects/actor_snapshot.rbs
|
|
482
485
|
- sig/generated/lib/solid_objects/actor_view.rbs
|
|
483
486
|
- sig/generated/lib/solid_objects/administration.rbs
|
|
@@ -505,6 +508,7 @@ files:
|
|
|
505
508
|
- sig/generated/lib/solid_objects/doctor.rbs
|
|
506
509
|
- sig/generated/lib/solid_objects/dom_identity.rbs
|
|
507
510
|
- sig/generated/lib/solid_objects/effect_executor.rbs
|
|
511
|
+
- sig/generated/lib/solid_objects/effect_payload.rbs
|
|
508
512
|
- sig/generated/lib/solid_objects/effect_registry.rbs
|
|
509
513
|
- sig/generated/lib/solid_objects/engine.rbs
|
|
510
514
|
- sig/generated/lib/solid_objects/errors.rbs
|
|
@@ -561,6 +565,7 @@ files:
|
|
|
561
565
|
- sig/generated/models/solid_objects/ready_message.rbs
|
|
562
566
|
- sig/generated/models/solid_objects/record.rbs
|
|
563
567
|
- sig/generated/models/solid_objects/reminder.rbs
|
|
568
|
+
- sig/public/effect_payload.rbs
|
|
564
569
|
- sig/support/framework.rbs
|
|
565
570
|
- web/assets/javascripts/application.js
|
|
566
571
|
- web/assets/javascripts/charts.js
|