saga_machines 0.1.5-x86_64-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 +7 -0
- data/CHANGELOG.md +43 -0
- data/LICENSE.txt +21 -0
- data/README.md +215 -0
- data/ext/saga_machines_native/core/CHANGELOG.md +36 -0
- data/ext/saga_machines_native/core/README.md +33 -0
- data/ext/saga_machines_native/extconf.rb +2 -0
- data/lib/saga_machines/version.rb +4 -0
- data/lib/saga_machines.rb +3 -0
- data/lib/saga_machines_native/saga_machines_native.so +0 -0
- data/sig/saga_machines.rbs +16 -0
- metadata +60 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0b1ae867a5bb8584ba3e03caa305889c6611c6338df228cfdf3d55140ce45490
|
|
4
|
+
data.tar.gz: 9c1495642d5e789e840abad8798076d280118c9c6c23b592b1573903773d994e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ab901036c5d9376e9d7e3de5a4bd0f17c4c5e3a95b89b7a7e110d0c952bc8879a0fbf3fc39c3c12c6f2631a0c8dc5c5c72ea7c4aacdc5c386d11b86c5a726223
|
|
7
|
+
data.tar.gz: 9b75c1080a3cdd39002ccaa5d17ca4fce06c37d9b1b77117e4c7b1a6ac0ad750ecfc8dbe11a0e30e0e2a36e8f2db58f1983aa4ed7dcb7aa46cba22dce783bbb8
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.5](https://github.com/seuros/saga_machines/compare/saga_machines/v0.1.4...saga_machines/v0.1.5) (2026-11-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* build against dedup-machines 0.3 ([fa36da9](https://github.com/seuros/saga_machines/commit/fa36da96c3aab595ff4daaa421a1f3e0d7c02fe9))
|
|
9
|
+
* require dedup-machines 0.3 ([e192ae3](https://github.com/seuros/saga_machines/commit/e192ae3fb7c33882826dfc56c3582cd2e685e6a3))
|
|
10
|
+
|
|
11
|
+
## [0.1.4](https://github.com/seuros/saga_machines/compare/saga_machines/v0.1.3...saga_machines/v0.1.4) (2026-11-06)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* restore a saga from persisted progress ([6c98ddd](https://github.com/seuros/saga_machines/commit/6c98ddd8fc44b880dc8bf195f8d5a8e32048b423))
|
|
17
|
+
|
|
18
|
+
## [0.1.3](https://github.com/seuros/saga_machines/compare/saga_machines/v0.1.2...saga_machines/v0.1.3) (2026-11-06)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* crates.io keywords and categories for the core ([660b649](https://github.com/seuros/saga_machines/commit/660b649c5b0229ab715571ecb0b97270dcaacfab))
|
|
24
|
+
|
|
25
|
+
## [0.1.2](https://github.com/seuros/saga_machines/compare/saga_machines/v0.1.1...saga_machines/v0.1.2) (2026-11-06)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
* keep test sources out of the packaged gem and crate ([38c7ba8](https://github.com/seuros/saga_machines/commit/38c7ba8523f9ad783b258df3df15e2e2b5f3b6a0))
|
|
31
|
+
|
|
32
|
+
## [0.1.1](https://github.com/seuros/saga_machines/compare/saga_machines-v0.1.0...saga_machines/v0.1.1) (2026-11-06)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Features
|
|
36
|
+
|
|
37
|
+
* initial extraction ([5c83b4d](https://github.com/seuros/saga_machines/commit/5c83b4d32f62e4e8074f5cf1e08f9756bbc3ccfe))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Bug Fixes
|
|
41
|
+
|
|
42
|
+
* depend on the published dedup-machines crate ([d3dc0aa](https://github.com/seuros/saga_machines/commit/d3dc0aaee5b40d7e969ab8973aac098c67b3411d))
|
|
43
|
+
* name the gemspec block spec so the release workflow detects the extension ([fe76b8d](https://github.com/seuros/saga_machines/commit/fe76b8d64e1ba6677df891aa9037a57b030c64c9))
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abdelkader Boudih
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# SagaMachines
|
|
2
|
+
|
|
3
|
+
> The return itinerary for expeditions that don't make it. 🔄
|
|
4
|
+
|
|
5
|
+
A saga coordinator for Ruby. You tell it how many steps the journey has, it tells you which step to run next, you report how it went. When a step fails, it walks you back through every step that already succeeded, in reverse, until the world looks like you never left.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gem 'saga_machines'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
saga = SagaMachines::Saga.new(order.id, steps: 3)
|
|
15
|
+
|
|
16
|
+
while (action = saga.next_action)
|
|
17
|
+
outcome = case [action.kind, action.step]
|
|
18
|
+
when [:forward, 0] then reserve_flight(order)
|
|
19
|
+
when [:forward, 1] then reserve_hotel(order)
|
|
20
|
+
when [:forward, 2] then reserve_car(order)
|
|
21
|
+
when [:compensate, 0] then release_flight(order)
|
|
22
|
+
when [:compensate, 1] then release_hotel(order)
|
|
23
|
+
when [:compensate, 2] then release_car(order)
|
|
24
|
+
end
|
|
25
|
+
saga.resolve(action, outcome ? :success : :failure)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
saga.progress # => [:complete, nil] or [:aborted, nil]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
That's the whole gem. One object, five methods, no DSL to memorize at 3 AM.
|
|
32
|
+
|
|
33
|
+
## A Message to the Resistance
|
|
34
|
+
|
|
35
|
+
So you shipped the checkout flow. Flight reserved, hotel reserved, then the car rental API returned a 503 and your customer now owns a hotel room in Lisbon with no way to get there.
|
|
36
|
+
|
|
37
|
+
You know what the fix is. You've known since the first time you drew three boxes on a whiteboard and an arrow labeled "rollback" that nobody ever implemented. The fix is a saga: every forward step gets a compensating step, and when something breaks, you run the compensations in reverse order.
|
|
38
|
+
|
|
39
|
+
The hard part was never the idea. The hard part is the bookkeeping. Which steps succeeded? Which compensation are we on? Did that retry already run? Can we still cancel? That bookkeeping is this gem. The reservations and the cancellations are still yours. We just promise never to lose count.
|
|
40
|
+
|
|
41
|
+
## Chapter 1: Stardate 2025.186, the AMS Garcia-Molina
|
|
42
|
+
|
|
43
|
+
> **AMS Garcia-Molina**, NCC-4217, *Garcia-Molina*-class recovery carrier.
|
|
44
|
+
> A failed expedition needs a return itinerary, not a promise to reverse time.
|
|
45
|
+
|
|
46
|
+
The carrier doesn't undo anything itself. It holds the flight plan. Three legs out, and if leg three is scrubbed, it orders legs two and one flown back, in that order, by the same crews that flew them out.
|
|
47
|
+
|
|
48
|
+
Somewhere on the bridge, a junior officer suggests:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
def book_trip
|
|
52
|
+
reserve_flight
|
|
53
|
+
reserve_hotel
|
|
54
|
+
reserve_car
|
|
55
|
+
rescue
|
|
56
|
+
# TODO: undo stuff
|
|
57
|
+
end
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
"That," says the recovery officer, "is how customers end up owning hotel rooms."
|
|
61
|
+
|
|
62
|
+
## The Flight Plan
|
|
63
|
+
|
|
64
|
+
Every saga is in exactly one of four states. Two of them are final.
|
|
65
|
+
|
|
66
|
+
```mermaid
|
|
67
|
+
stateDiagram-v2
|
|
68
|
+
[*] --> forward
|
|
69
|
+
forward --> forward: step succeeds, more to go
|
|
70
|
+
forward --> complete: last step succeeds
|
|
71
|
+
forward --> compensating: step fails, earlier steps done
|
|
72
|
+
forward --> aborted: step fails or cancel, nothing done yet
|
|
73
|
+
forward --> compensating: cancel, earlier steps done
|
|
74
|
+
compensating --> compensating: compensation fails, same step retried
|
|
75
|
+
compensating --> compensating: compensation succeeds, earlier steps remain
|
|
76
|
+
compensating --> aborted: last compensation succeeds
|
|
77
|
+
complete --> [*]
|
|
78
|
+
aborted --> [*]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
And here is the Lisbon trip, the day the car rental went down:
|
|
82
|
+
|
|
83
|
+
```mermaid
|
|
84
|
+
sequenceDiagram
|
|
85
|
+
participant You
|
|
86
|
+
participant Saga
|
|
87
|
+
participant Flight
|
|
88
|
+
participant Hotel
|
|
89
|
+
participant Car
|
|
90
|
+
|
|
91
|
+
You->>Saga: next_action
|
|
92
|
+
Saga-->>You: step 0, forward
|
|
93
|
+
You->>Flight: reserve
|
|
94
|
+
Flight-->>You: ok
|
|
95
|
+
You->>Saga: resolve(success)
|
|
96
|
+
|
|
97
|
+
You->>Saga: next_action
|
|
98
|
+
Saga-->>You: step 1, forward
|
|
99
|
+
You->>Hotel: reserve
|
|
100
|
+
Hotel-->>You: ok
|
|
101
|
+
You->>Saga: resolve(success)
|
|
102
|
+
|
|
103
|
+
You->>Saga: next_action
|
|
104
|
+
Saga-->>You: step 2, forward
|
|
105
|
+
You->>Car: reserve
|
|
106
|
+
Car-->>You: 503
|
|
107
|
+
You->>Saga: resolve(failure)
|
|
108
|
+
|
|
109
|
+
Note over Saga: compensating, step 1
|
|
110
|
+
You->>Saga: next_action
|
|
111
|
+
Saga-->>You: step 1, compensate
|
|
112
|
+
You->>Hotel: release
|
|
113
|
+
Hotel-->>You: ok
|
|
114
|
+
You->>Saga: resolve(success)
|
|
115
|
+
|
|
116
|
+
You->>Saga: next_action
|
|
117
|
+
Saga-->>You: step 0, compensate
|
|
118
|
+
You->>Flight: release
|
|
119
|
+
Flight-->>You: ok
|
|
120
|
+
You->>Saga: resolve(success)
|
|
121
|
+
|
|
122
|
+
Note over Saga: aborted. Nobody owns a hotel room.
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## How a Journey Unfolds
|
|
126
|
+
|
|
127
|
+
### Forward
|
|
128
|
+
|
|
129
|
+
Each call to `next_action` hands you the next leg. It carries a `step` number and a `kind`, which is `:forward` on the way out.
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
saga = SagaMachines::Saga.new(42, steps: 3)
|
|
133
|
+
|
|
134
|
+
action = saga.next_action
|
|
135
|
+
action.step # => 0
|
|
136
|
+
action.kind # => :forward
|
|
137
|
+
saga.resolve(action, :success)
|
|
138
|
+
|
|
139
|
+
saga.progress # => [:forward, 1]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Resolve every step with `:success` and the saga lands at `[:complete, nil]`. `next_action` returns `nil` from then on. There is nothing left to do.
|
|
143
|
+
|
|
144
|
+
### Something breaks
|
|
145
|
+
|
|
146
|
+
Report `:failure` on a forward step and the saga turns around. It only compensates steps that actually succeeded, and it compensates them newest first.
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
saga = SagaMachines::Saga.new(42, steps: 4)
|
|
150
|
+
3.times { saga.resolve(saga.next_action, :success) } # steps 0, 1, 2 done
|
|
151
|
+
|
|
152
|
+
failed = saga.next_action # step 3
|
|
153
|
+
saga.resolve(failed, :failure)
|
|
154
|
+
|
|
155
|
+
saga.progress # => [:compensating, 2]
|
|
156
|
+
saga.next_action # => step 2, kind :compensate
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Step 3 never succeeded, so it's never compensated. Step 2 is undone first, then 1, then 0. When the last compensation lands, progress reads `[:aborted, nil]`.
|
|
160
|
+
|
|
161
|
+
### A compensation fails too
|
|
162
|
+
|
|
163
|
+
Release-the-hotel can fail as easily as reserve-the-hotel. The saga doesn't skip it and doesn't give up. It hands you the same step again with a fresh attempt.
|
|
164
|
+
|
|
165
|
+
```ruby
|
|
166
|
+
undo = saga.next_action # step 2, :compensate
|
|
167
|
+
saga.resolve(undo, :failure)
|
|
168
|
+
|
|
169
|
+
again = saga.next_action # step 2, :compensate, new attempt
|
|
170
|
+
undo.same_key?(again) # => true, same leg
|
|
171
|
+
saga.resolve(undo, :success) # => false, that attempt is over
|
|
172
|
+
saga.resolve(again, :success) # => true
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The old handle is dead. A late reply to a retry you already moved on from cannot advance the saga, no matter how convincing it looks.
|
|
176
|
+
|
|
177
|
+
### Changing your mind
|
|
178
|
+
|
|
179
|
+
`cancel` is allowed between actions, never during one. If a step is in flight, you don't get to pretend it isn't.
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
saga = SagaMachines::Saga.new(7, steps: 2)
|
|
183
|
+
saga.resolve(saga.next_action, :success) # step 0 done, nothing pending
|
|
184
|
+
|
|
185
|
+
saga.cancel # => true
|
|
186
|
+
saga.progress # => [:compensating, 0]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Call `cancel` while an action is outstanding and it returns `false`. Resolve the action first, then cancel. A fresh saga with nothing done cancels straight to `[:aborted, nil]`.
|
|
190
|
+
|
|
191
|
+
## The Rules of the Carrier
|
|
192
|
+
|
|
193
|
+
- **Steps are exact.** `steps:` accepts 0, 1, 2, 3, 4, 8, or 16. Anything else raises `ArgumentError`. Zero steps is already complete.
|
|
194
|
+
- **Identity is an Integer** in `0..2**64-1`. Use your order id, your job id, whatever you'd put on the manifest. Floats and strings raise `TypeError`.
|
|
195
|
+
- **Every step is compensatable.** If you have a step that can't be undone, put it last, so nothing after it can fail.
|
|
196
|
+
- **A forward failure means nothing happened.** If the car API timed out and you don't know whether it booked, find out before you report. Reporting `:failure` on a step that secretly succeeded is how you leak a car.
|
|
197
|
+
- **Handles belong to one saga.** An action from one `Saga` instance is rejected by another, even with the same identity. `resolve` returns `false` for stale or foreign handles. It never raises for them.
|
|
198
|
+
- **Frozen means frozen.** `freeze` the saga and every mutation raises `FrozenError`.
|
|
199
|
+
|
|
200
|
+
## What You Think You're Doing vs Reality
|
|
201
|
+
|
|
202
|
+
### You Think: "I'll wrap it in a database transaction."
|
|
203
|
+
### Reality: Stripe is not in your database.
|
|
204
|
+
|
|
205
|
+
Transactions roll back rows. They do not unreserve a flight, refund a card, or recall an email. For anything that leaves your process, the only rollback is a forward action that cancels the previous one. That's a saga, and now you have one.
|
|
206
|
+
|
|
207
|
+
## What's Yours
|
|
208
|
+
|
|
209
|
+
The saga remembers where you are. It does not remember it for you across a crash. Persist the action before you execute it, persist the outcome before you resolve it, and on restart replay what you stored. It also doesn't schedule retries or wait for anything. Call `next_action` when you're ready, not before.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT License. See [LICENSE.txt](LICENSE.txt) for details.
|
|
214
|
+
|
|
215
|
+
**Remember: In space, nobody can hear your rollback. But they can see the hotel charge on their statement.**
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.3.1](https://github.com/seuros/saga_machines/compare/saga-machines-v0.3.0...saga-machines-v0.3.1) (2026-11-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* build against dedup-machines 0.3 ([fa36da9](https://github.com/seuros/saga_machines/commit/fa36da96c3aab595ff4daaa421a1f3e0d7c02fe9))
|
|
9
|
+
|
|
10
|
+
## [0.3.0](https://github.com/seuros/saga_machines/compare/saga-machines-v0.2.2...saga-machines-v0.3.0) (2026-11-06)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* restore a saga from persisted progress ([6c98ddd](https://github.com/seuros/saga_machines/commit/6c98ddd8fc44b880dc8bf195f8d5a8e32048b423))
|
|
16
|
+
|
|
17
|
+
## [0.2.2](https://github.com/seuros/saga_machines/compare/saga-machines-v0.2.1...saga-machines-v0.2.2) (2026-11-06)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* crates.io keywords and categories for the core ([660b649](https://github.com/seuros/saga_machines/commit/660b649c5b0229ab715571ecb0b97270dcaacfab))
|
|
23
|
+
|
|
24
|
+
## [0.2.1](https://github.com/seuros/saga_machines/compare/saga-machines-v0.2.0...saga-machines-v0.2.1) (2026-11-06)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* keep test sources out of the packaged gem and crate ([38c7ba8](https://github.com/seuros/saga_machines/commit/38c7ba8523f9ad783b258df3df15e2e2b5f3b6a0))
|
|
30
|
+
|
|
31
|
+
## [0.2.0](https://github.com/seuros/saga_machines/compare/saga-machines-v0.1.0...saga-machines-v0.2.0) (2026-11-06)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* initial extraction ([5c83b4d](https://github.com/seuros/saga_machines/commit/5c83b4d32f62e4e8074f5cf1e08f9756bbc3ccfe))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# saga-machines
|
|
2
|
+
|
|
3
|
+
> **AMS Garcia-Molina**, NCC-4217, *Garcia-Molina*-class recovery carrier.
|
|
4
|
+
|
|
5
|
+
Engine-room flight manual: chart forward maneuvers and compensating return legs.
|
|
6
|
+
|
|
7
|
+
Allocation-free `no_std` sequential saga decisions. Successful forward steps are
|
|
8
|
+
compensated in reverse order after a known forward failure. Failed compensations
|
|
9
|
+
remain at the same step for a fresh retry attempt; stale/duplicate replies cannot
|
|
10
|
+
advance progress. Every step is assumed compensatable. Cancellation is allowed
|
|
11
|
+
only between actions, never by forgetting an unresolved external effect.
|
|
12
|
+
|
|
13
|
+
Action keys remain stable across retries and can claim an external `dedup-machines`
|
|
14
|
+
ledger. Attempt handles change to reject stale replies. A forward failure must mean
|
|
15
|
+
**no effect occurred**; uncertain effects must be reconciled before reporting.
|
|
16
|
+
Handles are scoped to one workflow lifetime.
|
|
17
|
+
|
|
18
|
+
This model does not make effects or progress durable. Persist actions before
|
|
19
|
+
executing them and outcomes before advancing; provide transactional/idempotent
|
|
20
|
+
effects and crash recovery externally. Compensation is not atomic rollback.
|
|
21
|
+
No payloads, retry timing, wire checkpoint, or Ruby binding.
|
|
22
|
+
|
|
23
|
+
`snapshot()` exports the resolved progress and attempt count; `Saga::restore`
|
|
24
|
+
rebuilds the workflow after a restart and rejects progress that does not fit the
|
|
25
|
+
step count. An attempt that was issued but never resolved is not carried over:
|
|
26
|
+
the restored saga reissues the same action key under a fresh attempt, so a reply
|
|
27
|
+
to the pre-restart attempt is rejected and the external ledger decides whether
|
|
28
|
+
the effect already happened.
|
|
29
|
+
|
|
30
|
+
String identities such as manifest ids map to the `u64` namespace through
|
|
31
|
+
`SagaId::from_bytes` (FNV-1a, deterministic across processes), so action keys
|
|
32
|
+
stay stable across restarts. The caller owns collision avoidance within one
|
|
33
|
+
ledger; `SagaId::from_raw` adopts an identity allocated elsewhere.
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module SagaMachines
|
|
2
|
+
VERSION: String
|
|
3
|
+
class Action
|
|
4
|
+
def step: () -> Integer
|
|
5
|
+
def kind: () -> (:forward | :compensate)
|
|
6
|
+
def same_key?: (Action) -> bool
|
|
7
|
+
end
|
|
8
|
+
class Saga
|
|
9
|
+
def self.new: (Integer identity, steps: Integer) -> Saga
|
|
10
|
+
def steps: () -> Integer
|
|
11
|
+
def next_action: () -> Action?
|
|
12
|
+
def resolve: (Action, :success | :failure) -> bool
|
|
13
|
+
def cancel: () -> bool
|
|
14
|
+
def progress: () -> [Symbol, Integer?]
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: saga_machines
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.5
|
|
5
|
+
platform: x86_64-linux
|
|
6
|
+
authors:
|
|
7
|
+
- Abdelkader Boudih
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-11-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Local unstable saga model, not a durable workflow or exactly-once runtime.
|
|
14
|
+
email:
|
|
15
|
+
- oss@seuros.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- CHANGELOG.md
|
|
21
|
+
- LICENSE.txt
|
|
22
|
+
- README.md
|
|
23
|
+
- ext/saga_machines_native/core/CHANGELOG.md
|
|
24
|
+
- ext/saga_machines_native/core/README.md
|
|
25
|
+
- ext/saga_machines_native/extconf.rb
|
|
26
|
+
- lib/saga_machines.rb
|
|
27
|
+
- lib/saga_machines/version.rb
|
|
28
|
+
- lib/saga_machines_native/saga_machines_native.so
|
|
29
|
+
- sig/saga_machines.rbs
|
|
30
|
+
homepage: https://github.com/seuros/saga_machines
|
|
31
|
+
licenses:
|
|
32
|
+
- MIT
|
|
33
|
+
metadata:
|
|
34
|
+
source_code_uri: https://github.com/seuros/saga_machines
|
|
35
|
+
rubygems_mfa_required: 'true'
|
|
36
|
+
cargo_crate_name: saga_machines_native
|
|
37
|
+
cargo_manifest_path: ext/saga_machines_native/ffi/Cargo.toml
|
|
38
|
+
post_install_message:
|
|
39
|
+
rdoc_options: []
|
|
40
|
+
require_paths:
|
|
41
|
+
- lib
|
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '4.0'
|
|
47
|
+
- - "<"
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: 4.1.dev
|
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubygems_version: 3.5.23
|
|
57
|
+
signing_key:
|
|
58
|
+
specification_version: 4
|
|
59
|
+
summary: Initial native sequential saga and reverse compensation policies
|
|
60
|
+
test_files: []
|