solid_objects 0.17.2 → 0.17.4
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 +26 -0
- data/README.md +11 -0
- data/docs/agents.md +7 -0
- data/docs/guides/expiring-reservations.md +175 -0
- data/docs/guides/ordered-jobs.md +232 -0
- data/docs/guides/race-conditions.md +236 -0
- data/docs/guides/transactional-outbox.md +156 -0
- data/docs/roadmap.md +2 -1
- data/examples/guides/expiring_reservations/seat_inventory.rb +81 -0
- data/examples/guides/ordered_jobs/account.rb +23 -0
- data/examples/guides/ordered_jobs/apply_entry_job.rb +9 -0
- data/examples/guides/ordered_jobs/apply_entry_unordered_job.rb +7 -0
- data/examples/guides/ordered_jobs/create_ledger_entries.rb +14 -0
- data/examples/guides/ordered_jobs/ledger_account.rb +22 -0
- data/examples/guides/ordered_jobs/ledger_entry.rb +4 -0
- data/examples/guides/ordered_jobs/solid_objects.rb +10 -0
- data/examples/guides/race_conditions/event.rb +15 -0
- data/examples/guides/race_conditions/event_tickets.rb +66 -0
- data/examples/guides/transactional_outbox/checkout.rb +22 -0
- data/examples/guides/transactional_outbox/order.rb +17 -0
- data/examples/guides/transactional_outbox/outbox_message.rb +14 -0
- data/examples/guides/transactional_outbox/shipment_job.rb +8 -0
- data/examples/guides/transactional_outbox/solid_objects.rb +12 -0
- data/lib/solid_objects/activation.rb +1 -0
- data/lib/solid_objects/lease.rb +1 -0
- data/lib/solid_objects/version.rb +1 -1
- metadata +21 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
|
|
3
|
+
class Checkout < SolidObjects::Actor
|
|
4
|
+
attribute :status, default: "open"
|
|
5
|
+
attribute :total_cents, default: 0
|
|
6
|
+
attribute :shipment_id, default: nil
|
|
7
|
+
|
|
8
|
+
def place(total_cents:)
|
|
9
|
+
return status unless status == "open"
|
|
10
|
+
|
|
11
|
+
self.status = "placed"
|
|
12
|
+
self.total_cents = total_cents
|
|
13
|
+
commit_action(:record_order, reference: actor_id, total_cents:)
|
|
14
|
+
emit(:request_shipment, order_reference: actor_id, on_success: :shipment_requested)
|
|
15
|
+
status
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def shipment_requested(effect_id:, arguments:, result:)
|
|
19
|
+
self.status = "shipping"
|
|
20
|
+
self.shipment_id = result.fetch("shipment_id")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
|
|
3
|
+
class Order < ApplicationRecord
|
|
4
|
+
def self.place_and_enqueue!(reference:, total_cents:)
|
|
5
|
+
order = create!(reference:, total_cents:)
|
|
6
|
+
ShipmentJob.perform_later(order_id: order.id)
|
|
7
|
+
order
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.place_with_outbox!(reference:, total_cents:)
|
|
11
|
+
transaction do
|
|
12
|
+
order = create!(reference:, total_cents:)
|
|
13
|
+
OutboxMessage.create!(name: "request_shipment", arguments: { "order_id" => order.id })
|
|
14
|
+
order
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
|
|
3
|
+
class OutboxMessage < ApplicationRecord
|
|
4
|
+
JOBS = { "request_shipment" => ShipmentJob }.freeze
|
|
5
|
+
|
|
6
|
+
scope :pending, -> { where(delivered_at: nil).order(:id) }
|
|
7
|
+
|
|
8
|
+
def self.relay(limit: 100)
|
|
9
|
+
pending.limit(limit).each do |message|
|
|
10
|
+
JOBS.fetch(message.name).perform_later(**message.arguments.symbolize_keys)
|
|
11
|
+
message.update!(delivered_at: Time.current)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
|
|
3
|
+
SolidObjects.register_commit_action(:record_order) do |arguments, _context|
|
|
4
|
+
Order.create!(reference: arguments.fetch("reference"), total_cents: arguments.fetch("total_cents"))
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
SolidObjects.register_effect(:request_shipment) do |arguments, context|
|
|
8
|
+
ShippingProvider.create_shipment(
|
|
9
|
+
idempotency_key: context.id,
|
|
10
|
+
order_reference: arguments.fetch("order_reference")
|
|
11
|
+
)
|
|
12
|
+
end
|
data/lib/solid_objects/lease.rb
CHANGED
|
@@ -123,6 +123,7 @@ module SolidObjects
|
|
|
123
123
|
instance = Instance.lock.find_by(id: instance_id)
|
|
124
124
|
next false unless instance
|
|
125
125
|
next false unless owned_generation?(instance)
|
|
126
|
+
next false if ClaimedMessage.where(instance_id:).exists?
|
|
126
127
|
|
|
127
128
|
instance.update!(
|
|
128
129
|
activation_owner_id: nil,
|
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.17.
|
|
4
|
+
version: 0.17.4
|
|
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-10-
|
|
11
|
+
date: 2026-10-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: actioncable
|
|
@@ -362,6 +362,10 @@ files:
|
|
|
362
362
|
- docs/development.md
|
|
363
363
|
- docs/effect-recovery.md
|
|
364
364
|
- docs/fit.md
|
|
365
|
+
- docs/guides/expiring-reservations.md
|
|
366
|
+
- docs/guides/ordered-jobs.md
|
|
367
|
+
- docs/guides/race-conditions.md
|
|
368
|
+
- docs/guides/transactional-outbox.md
|
|
365
369
|
- docs/implementation-plan.md
|
|
366
370
|
- docs/local-testing.md
|
|
367
371
|
- docs/migrating-existing-state.md
|
|
@@ -391,6 +395,21 @@ files:
|
|
|
391
395
|
- examples/at_least_once/demo.rb
|
|
392
396
|
- examples/at_least_once/effect_worker.rb
|
|
393
397
|
- examples/at_least_once/sink.rb
|
|
398
|
+
- examples/guides/expiring_reservations/seat_inventory.rb
|
|
399
|
+
- examples/guides/ordered_jobs/account.rb
|
|
400
|
+
- examples/guides/ordered_jobs/apply_entry_job.rb
|
|
401
|
+
- examples/guides/ordered_jobs/apply_entry_unordered_job.rb
|
|
402
|
+
- examples/guides/ordered_jobs/create_ledger_entries.rb
|
|
403
|
+
- examples/guides/ordered_jobs/ledger_account.rb
|
|
404
|
+
- examples/guides/ordered_jobs/ledger_entry.rb
|
|
405
|
+
- examples/guides/ordered_jobs/solid_objects.rb
|
|
406
|
+
- examples/guides/race_conditions/event.rb
|
|
407
|
+
- examples/guides/race_conditions/event_tickets.rb
|
|
408
|
+
- examples/guides/transactional_outbox/checkout.rb
|
|
409
|
+
- examples/guides/transactional_outbox/order.rb
|
|
410
|
+
- examples/guides/transactional_outbox/outbox_message.rb
|
|
411
|
+
- examples/guides/transactional_outbox/shipment_job.rb
|
|
412
|
+
- examples/guides/transactional_outbox/solid_objects.rb
|
|
394
413
|
- examples/quickstart/README.md
|
|
395
414
|
- examples/quickstart/app/actors/ticket_sale.rb
|
|
396
415
|
- examples/quickstart/smoke.rb
|