-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path1-simple.js
More file actions
95 lines (87 loc) · 2.15 KB
/
1-simple.js
File metadata and controls
95 lines (87 loc) · 2.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
'use strict';
const accounts = {
buyer: { balance: 70 },
merchant: { balance: 40 },
};
const inventory = { total: 2 };
const compensate = (executed, context) => {
for (const completed of executed.toReversed()) {
if (!completed.compensation) continue;
try {
completed.compensation(context);
console.log(`↩ Undo ${completed.name}`);
} catch (rollbackError) {
console.error(`⚠ Compensation failed: ${rollbackError.message}`);
}
}
};
const saga = (steps, context) => {
const executed = [];
for (const current of steps) {
try {
current.action(context);
executed.push(current);
console.log(`✓ ${current.name}`);
} catch (error) {
console.error(`✗ ${current.name}: ${error.message}`);
compensate(executed, context);
throw error;
}
}
};
const steps = [
{
name: 'Check buyer balance',
action({ from, amount }) {
const wallet = accounts[from];
if (!wallet || wallet.balance < amount) {
throw new Error('Not enough funds');
}
},
},
{
name: 'Reserve item',
action() {
if (inventory.total <= 0) throw new Error('Inventory empty');
inventory.total -= 1;
},
compensation() {
inventory.total += 1;
},
},
{
name: 'Charge buyer',
action({ from, amount }) {
accounts[from].balance -= amount;
},
compensation({ from, amount }) {
accounts[from].balance += amount;
},
},
{
name: 'Pay merchant',
action({ to, amount }) {
accounts[to].balance += amount;
},
compensation({ to, amount }) {
accounts[to].balance -= amount;
},
},
];
const printState = (label) => {
console.log(`\n${label}`);
console.log(`Buyer balance: ${accounts.buyer.balance}`);
console.log(`Merchant balance: ${accounts.merchant.balance}`);
console.log(`Inventory left: ${inventory.total}`);
};
const purchase = (amount) => {
printState(`Before purchase of ${amount}`);
try {
saga(steps, { from: 'buyer', to: 'merchant', amount });
printState(`Purchase completed successfully`);
} catch {
printState(`Purchase rolled back`);
}
};
purchase(30);
purchase(50);