solid_objects 0.1.0 → 0.2.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +67 -37
  4. data/app/models/solid_objects/claimed_message.rb +2 -0
  5. data/app/models/solid_objects/message.rb +6 -1
  6. data/benchmark/support.rb +10 -15
  7. data/benchmark/{ask_latency.rb → sync_latency.rb} +1 -1
  8. data/db/migrate/20260805000000_create_solid_objects_tables.rb +15 -3
  9. data/docs/adr/0006-at-least-once-delivery.md +1 -1
  10. data/docs/adr/0008-actor-communication.md +4 -1
  11. data/docs/adr/0011-wake-up-strategy.md +13 -4
  12. data/docs/architecture.md +51 -20
  13. data/docs/benchmarks.md +9 -9
  14. data/docs/correctness.md +28 -9
  15. data/docs/database-schema.md +15 -7
  16. data/docs/development.md +3 -3
  17. data/docs/implementation-plan.md +22 -16
  18. data/docs/operations.md +3 -3
  19. data/docs/research/solid_queue.md +2 -1
  20. data/docs/roadmap.md +5 -2
  21. data/docs/security.md +4 -2
  22. data/lib/solid_objects/activation.rb +35 -19
  23. data/lib/solid_objects/activation_manager.rb +22 -6
  24. data/lib/solid_objects/actor.rb +16 -3
  25. data/lib/solid_objects/caller_process.rb +57 -0
  26. data/lib/solid_objects/client.rb +6 -37
  27. data/lib/solid_objects/configuration.rb +4 -4
  28. data/lib/solid_objects/engine.rb +1 -0
  29. data/lib/solid_objects/errors.rb +17 -1
  30. data/lib/solid_objects/executor.rb +42 -2
  31. data/lib/solid_objects/lease.rb +22 -10
  32. data/lib/solid_objects/message_reference.rb +1 -0
  33. data/lib/solid_objects/process_registry.rb +5 -1
  34. data/lib/solid_objects/reference.rb +8 -8
  35. data/lib/solid_objects/synchronous_invocation.rb +93 -0
  36. data/lib/solid_objects/version.rb +1 -1
  37. data/lib/solid_objects.rb +7 -0
  38. data/sig/generated/lib/solid_objects/activation.rbs +6 -0
  39. data/sig/generated/lib/solid_objects/activation_manager.rbs +6 -0
  40. data/sig/generated/lib/solid_objects/actor.rbs +9 -6
  41. data/sig/generated/lib/solid_objects/caller_process.rbs +32 -0
  42. data/sig/generated/lib/solid_objects/client.rbs +2 -8
  43. data/sig/generated/lib/solid_objects/configuration.rbs +2 -2
  44. data/sig/generated/lib/solid_objects/errors.rbs +18 -1
  45. data/sig/generated/lib/solid_objects/executor.rbs +3 -0
  46. data/sig/generated/lib/solid_objects/lease.rbs +14 -10
  47. data/sig/generated/lib/solid_objects/reference.rbs +3 -3
  48. data/sig/generated/lib/solid_objects/synchronous_invocation.rbs +28 -0
  49. data/sig/generated/lib/solid_objects.rbs +3 -0
  50. data/sig/generated/models/solid_objects/message.rbs +3 -0
  51. metadata +8 -8
@@ -130,14 +130,17 @@ module SolidObjects
130
130
  # @rbs () -> MessageContext?
131
131
  def current_message: () -> MessageContext?
132
132
 
133
- # @rbs (Symbol | String, ?on_success: Symbol | String?, ?on_failure: Symbol | String?, **untyped) -> EffectIntent
134
- def emit: (Symbol | String, ?on_success: Symbol | String?, ?on_failure: Symbol | String?, **untyped) -> EffectIntent
133
+ # @rbs (Symbol | String, String, ?details: Hash[String | Symbol, untyped]) -> bot
134
+ def reject: (Symbol | String, String, ?details: Hash[String | Symbol, untyped]) -> bot
135
135
 
136
- # @rbs (Symbol | String, at: Time, ?every: Numeric?, ?missed: Symbol | String, arguments: Hash[Symbol | String, untyped]) -> ReminderIntent
137
- def schedule: (Symbol | String, at: Time, arguments: Hash[Symbol | String, untyped], ?every: Numeric?, ?missed: Symbol | String) -> ReminderIntent
136
+ # @rbs (Symbol | String, ?on_success: Symbol | String?, ?on_failure: Symbol | String?, **untyped) -> nil
137
+ def emit: (Symbol | String, ?on_success: Symbol | String?, ?on_failure: Symbol | String?, **untyped) -> nil
138
138
 
139
- # @rbs (Reference, Symbol | String, ?available_at: Time?, ?idempotency_key: String?, **untyped) -> OutboundMessageIntent
140
- def send_to: (Reference, Symbol | String, ?available_at: Time?, ?idempotency_key: String?, **untyped) -> OutboundMessageIntent
139
+ # @rbs (Symbol | String, at: Time, ?every: Numeric?, ?missed: Symbol | String, arguments: Hash[Symbol | String, untyped]) -> nil
140
+ def schedule: (Symbol | String, at: Time, arguments: Hash[Symbol | String, untyped], ?every: Numeric?, ?missed: Symbol | String) -> nil
141
+
142
+ # @rbs (Reference, Symbol | String, ?available_at: Time?, ?idempotency_key: String?, **untyped) -> nil
143
+ def send_to: (Reference, Symbol | String, ?available_at: Time?, ?idempotency_key: String?, **untyped) -> nil
141
144
 
142
145
  # @rbs (Symbol | String, Hash[String, untyped]) -> untyped
143
146
  def invoke: (Symbol | String, Hash[String, untyped]) -> untyped
@@ -0,0 +1,32 @@
1
+ # Generated from lib/solid_objects/caller_process.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class CallerProcess
5
+ @mutex: Thread::Mutex
6
+
7
+ @process_id: Integer?
8
+
9
+ @registry: ProcessRegistry?
10
+
11
+ # @rbs () -> void
12
+ def initialize: () -> void
13
+
14
+ # @rbs () -> ProcessRegistry
15
+ def process_registry: () -> ProcessRegistry
16
+
17
+ private
18
+
19
+ attr_reader mutex: untyped
20
+
21
+ attr_reader registry: untyped
22
+
23
+ # @rbs () -> void
24
+ def reset_after_fork: () -> void
25
+
26
+ # @rbs () -> bool
27
+ def reusable_registry?: () -> bool
28
+
29
+ # @rbs () -> ProcessRegistry
30
+ def register: () -> ProcessRegistry
31
+ end
32
+ end
@@ -8,10 +8,10 @@ module SolidObjects
8
8
  def initialize: (?mailbox: Mailbox) -> void
9
9
 
10
10
  # @rbs (Reference, Symbol | String, Hash[Symbol | String, untyped], ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped) -> MessageReference
11
- def tell: (Reference, Symbol | String, Hash[Symbol | String, untyped], ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped) -> MessageReference
11
+ def async: (Reference, Symbol | String, Hash[Symbol | String, untyped], ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped) -> MessageReference
12
12
 
13
13
  # @rbs (Reference, Symbol | String, Hash[Symbol | String, untyped], timeout: Numeric, ?idempotency_key: String?, ?authorization_context: untyped) -> untyped
14
- def ask: (Reference, Symbol | String, Hash[Symbol | String, untyped], timeout: Numeric, ?idempotency_key: String?, ?authorization_context: untyped) -> untyped
14
+ def sync: (Reference, Symbol | String, Hash[Symbol | String, untyped], timeout: Numeric, ?idempotency_key: String?, ?authorization_context: untyped) -> untyped
15
15
 
16
16
  # @rbs (Reference, ?authorization_context: untyped) -> bool
17
17
  def destroy: (Reference, ?authorization_context: untyped) -> bool
@@ -25,11 +25,5 @@ module SolidObjects
25
25
 
26
26
  # @rbs (Reference, authorization_context: untyped) -> void
27
27
  def authorize_destroy!: (Reference, authorization_context: untyped) -> void
28
-
29
- # @rbs (MessageReference, timeout: Numeric) -> untyped
30
- def wait_for_result: (MessageReference, timeout: Numeric) -> untyped
31
-
32
- # @rbs () -> Float
33
- def monotonic_now: () -> Float
34
28
  end
35
29
  end
@@ -44,7 +44,7 @@ module SolidObjects
44
44
 
45
45
  @polling_interval: Float
46
46
 
47
- @ask_polling_interval: Float
47
+ @sync_polling_interval: Float
48
48
 
49
49
  @lease_duration: Float
50
50
 
@@ -70,7 +70,7 @@ module SolidObjects
70
70
 
71
71
  attr_accessor polling_interval: untyped
72
72
 
73
- attr_accessor ask_polling_interval: untyped
73
+ attr_accessor sync_polling_interval: untyped
74
74
 
75
75
  attr_accessor lease_duration: untyped
76
76
 
@@ -40,7 +40,24 @@ module SolidObjects
40
40
  class ActorDestroyed < LostActivation
41
41
  end
42
42
 
43
- class AskTimeout < Error
43
+ class SyncTimeout < Error
44
+ end
45
+
46
+ class Rejected < Error
47
+ @code: String
48
+
49
+ @details: Hash[String, untyped]
50
+
51
+ @message_id: Integer?
52
+
53
+ attr_reader code: untyped
54
+
55
+ attr_reader details: untyped
56
+
57
+ attr_reader message_id: untyped
58
+
59
+ # @rbs (code: String | Symbol, message: String, ?details: Hash[String | Symbol, untyped], ?message_id: Integer?) -> void
60
+ def initialize: (code: String | Symbol, message: String, ?details: Hash[String | Symbol, untyped], ?message_id: Integer?) -> void
44
61
  end
45
62
 
46
63
  class MessageFailed < Error
@@ -45,6 +45,9 @@ module SolidObjects
45
45
  # @rbs (Exception) -> void
46
46
  def fail_message: (Exception) -> void
47
47
 
48
+ # @rbs (Rejected) -> void
49
+ def reject_message: (Rejected) -> void
50
+
48
51
  # @rbs () -> ClaimedMessage
49
52
  def matching_claim!: () -> ClaimedMessage
50
53
 
@@ -2,35 +2,39 @@
2
2
 
3
3
  module SolidObjects
4
4
  class Lease
5
- # @rbs (instance: Instance, owner_id: String, now: Time, ?duration: Numeric, database_adapter: DatabaseAdapter) -> Lease?
6
- def self.claim: (instance: Instance, owner_id: String, now: Time, database_adapter: DatabaseAdapter, ?duration: Numeric) -> Lease?
5
+ # @rbs (instance: Instance, owner_id: String, activation_token: String, now: Time, ?duration: Numeric, database_adapter: DatabaseAdapter) -> Lease?
6
+ def self.claim: (instance: Instance, owner_id: String, activation_token: String, now: Time, database_adapter: DatabaseAdapter, ?duration: Numeric) -> Lease?
7
7
 
8
- # @rbs (instance_id: Integer, owner_id: String, ?duration: Numeric, ?database_adapter: DatabaseAdapter) -> Lease?
9
- def self.acquire: (instance_id: Integer, owner_id: String, ?duration: Numeric, ?database_adapter: DatabaseAdapter) -> Lease?
8
+ # @rbs (instance_id: Integer, owner_id: String, ?activation_token: String, ?duration: Numeric, ?database_adapter: DatabaseAdapter) -> Lease?
9
+ def self.acquire: (instance_id: Integer, owner_id: String, ?activation_token: String, ?duration: Numeric, ?database_adapter: DatabaseAdapter) -> Lease?
10
10
 
11
11
  # @rbs (Instance, String, Time) -> bool
12
12
  private def self.held_by_another_live_owner?: (Instance, String, Time) -> bool
13
13
 
14
- @instance_id: Integer
14
+ @database_adapter: DatabaseAdapter
15
15
 
16
- @owner_id: String
16
+ @expires_at: Time
17
17
 
18
18
  @generation: Integer
19
19
 
20
- @expires_at: Time
20
+ @activation_token: String
21
21
 
22
- @database_adapter: DatabaseAdapter
22
+ @owner_id: String
23
+
24
+ @instance_id: Integer
23
25
 
24
26
  attr_reader instance_id: untyped
25
27
 
26
28
  attr_reader owner_id: untyped
27
29
 
30
+ attr_reader activation_token: untyped
31
+
28
32
  attr_reader generation: untyped
29
33
 
30
34
  attr_reader expires_at: untyped
31
35
 
32
- # @rbs (instance_id: Integer, owner_id: String, generation: Integer, expires_at: Time, database_adapter: DatabaseAdapter) -> void
33
- def initialize: (instance_id: Integer, owner_id: String, generation: Integer, expires_at: Time, database_adapter: DatabaseAdapter) -> void
36
+ # @rbs (instance_id: Integer, owner_id: String, activation_token: String, generation: Integer, expires_at: Time, database_adapter: DatabaseAdapter) -> void
37
+ def initialize: (instance_id: Integer, owner_id: String, activation_token: String, generation: Integer, expires_at: Time, database_adapter: DatabaseAdapter) -> void
34
38
 
35
39
  # @rbs (?duration: Numeric) -> Lease
36
40
  def renew: (?duration: Numeric) -> Lease
@@ -13,11 +13,11 @@ module SolidObjects
13
13
  # @rbs (actor_type: String, actor_id: String) -> void
14
14
  def initialize: (actor_type: String, actor_id: String) -> void
15
15
 
16
- # @rbs (Symbol | String, ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> (MessageReference | Actor::OutboundMessageIntent)
17
- def tell: (Symbol | String, ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> (MessageReference | Actor::OutboundMessageIntent)
16
+ # @rbs (Symbol | String, ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> MessageReference?
17
+ def async: (Symbol | String, ?available_at: Time?, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> MessageReference?
18
18
 
19
19
  # @rbs (Symbol | String, ?timeout: Numeric, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> untyped
20
- def ask: (Symbol | String, ?timeout: Numeric, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> untyped
20
+ def sync: (Symbol | String, ?timeout: Numeric, ?idempotency_key: String?, ?authorization_context: untyped, **untyped) -> untyped
21
21
 
22
22
  # @rbs (?authorization_context: untyped) -> bool
23
23
  def destroy: (?authorization_context: untyped) -> bool
@@ -0,0 +1,28 @@
1
+ # Generated from lib/solid_objects/synchronous_invocation.rb with RBS::Inline
2
+
3
+ module SolidObjects
4
+ class SynchronousInvocation
5
+ # @rbs (MessageReference, timeout: Numeric) -> untyped
6
+ def call: (MessageReference, timeout: Numeric) -> untyped
7
+
8
+ private
9
+
10
+ # @rbs (MessageReference) -> Message
11
+ def load_message: (MessageReference) -> Message
12
+
13
+ # @rbs (Message) -> untyped
14
+ def completed_result: (Message) -> untyped
15
+
16
+ # @rbs (Message) -> bot
17
+ def raise_rejection: (Message) -> bot
18
+
19
+ # @rbs (Message, deadline: Float) -> Integer
20
+ def assist: (Message, deadline: Float) -> Integer
21
+
22
+ # @rbs (Numeric) -> void
23
+ def wait: (Numeric) -> void
24
+
25
+ # @rbs () -> Float
26
+ def monotonic_now: () -> Float
27
+ end
28
+ end
@@ -21,6 +21,9 @@ module SolidObjects
21
21
  # @rbs () -> Client
22
22
  def self.client: () -> Client
23
23
 
24
+ # @rbs () -> CallerProcess
25
+ def self.caller_process: () -> CallerProcess
26
+
24
27
  # @rbs () -> DeadLetterManager
25
28
  def self.dead_letters: () -> DeadLetterManager
26
29
 
@@ -11,6 +11,9 @@ module SolidObjects
11
11
  # @rbs () -> bool
12
12
  def completed?: () -> bool
13
13
 
14
+ # @rbs () -> bool
15
+ def rejected?: () -> bool
16
+
14
17
  # @rbs () -> bool
15
18
  def dead?: () -> bool
16
19
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_objects
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Carlson
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-08-06 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: actioncable
@@ -252,7 +251,6 @@ description: 'The Cloudflare Durable Objects programming model for Rails: addres
252
251
  objects with durable state, ordered mailboxes, fenced activation, per-object alarms,
253
252
  transactional effects, and reactive ERB. It runs on MySQL, PostgreSQL, and SQLite
254
253
  without requiring Redis.'
255
- email:
256
254
  executables:
257
255
  - solid_objects
258
256
  extensions: []
@@ -280,7 +278,6 @@ files:
280
278
  - app/views/solid_objects/instances/index.html.erb
281
279
  - app/views/solid_objects/instances/show.html.erb
282
280
  - benchmark/activation_cache.rb
283
- - benchmark/ask_latency.rb
284
281
  - benchmark/claim.rb
285
282
  - benchmark/cold_actors.rb
286
283
  - benchmark/concurrent_actors.rb
@@ -289,6 +286,7 @@ files:
289
286
  - benchmark/processing.rb
290
287
  - benchmark/query_count.rb
291
288
  - benchmark/support.rb
289
+ - benchmark/sync_latency.rb
292
290
  - config/routes.rb
293
291
  - db/migrate/20260805000000_create_solid_objects_tables.rb
294
292
  - docs/adr/0001-postgresql-backend.md
@@ -341,6 +339,7 @@ files:
341
339
  - lib/solid_objects/actor_snapshot.rb
342
340
  - lib/solid_objects/actor_view.rb
343
341
  - lib/solid_objects/broadcast_executor.rb
342
+ - lib/solid_objects/caller_process.rb
344
343
  - lib/solid_objects/cli.rb
345
344
  - lib/solid_objects/client.rb
346
345
  - lib/solid_objects/configuration.rb
@@ -370,6 +369,7 @@ files:
370
369
  - lib/solid_objects/stream_name.rb
371
370
  - lib/solid_objects/stream_token.rb
372
371
  - lib/solid_objects/supervisor.rb
372
+ - lib/solid_objects/synchronous_invocation.rb
373
373
  - lib/solid_objects/turbo_stream_renderer.rb
374
374
  - lib/solid_objects/version.rb
375
375
  - lib/solid_objects/wake_up.rb
@@ -390,6 +390,7 @@ files:
390
390
  - sig/generated/lib/solid_objects/actor_snapshot.rbs
391
391
  - sig/generated/lib/solid_objects/actor_view.rbs
392
392
  - sig/generated/lib/solid_objects/broadcast_executor.rbs
393
+ - sig/generated/lib/solid_objects/caller_process.rbs
393
394
  - sig/generated/lib/solid_objects/cli.rbs
394
395
  - sig/generated/lib/solid_objects/client.rbs
395
396
  - sig/generated/lib/solid_objects/configuration.rbs
@@ -419,6 +420,7 @@ files:
419
420
  - sig/generated/lib/solid_objects/stream_name.rbs
420
421
  - sig/generated/lib/solid_objects/stream_token.rbs
421
422
  - sig/generated/lib/solid_objects/supervisor.rbs
423
+ - sig/generated/lib/solid_objects/synchronous_invocation.rbs
422
424
  - sig/generated/lib/solid_objects/turbo_stream_renderer.rbs
423
425
  - sig/generated/lib/solid_objects/version.rbs
424
426
  - sig/generated/lib/solid_objects/wake_up.rbs
@@ -445,7 +447,6 @@ metadata:
445
447
  homepage_uri: https://solidobjects.dev
446
448
  rubygems_mfa_required: 'true'
447
449
  source_code_uri: https://github.com/cardmagic/solid_objects
448
- post_install_message:
449
450
  rdoc_options: []
450
451
  require_paths:
451
452
  - lib
@@ -460,8 +461,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
460
461
  - !ruby/object:Gem::Version
461
462
  version: '0'
462
463
  requirements: []
463
- rubygems_version: 3.5.22
464
- signing_key:
464
+ rubygems_version: 4.0.10
465
465
  specification_version: 4
466
466
  summary: Cloudflare Durable Objects, ported to Rails
467
467
  test_files: []