-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsaga-transaction.examples.js
More file actions
164 lines (147 loc) · 5.26 KB
/
saga-transaction.examples.js
File metadata and controls
164 lines (147 loc) · 5.26 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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/**
* Saga 事务集成示例
*/
const MonSQLize = require('../lib/index.js');
// 模拟外部服务
const mockServices = {
orders: {
create: async (data) => {
console.log('[订单服务] 创建订单:', data);
return { orderId: 'ORDER_' + Date.now(), ...data };
},
cancel: async (orderId) => {
console.log('[订单服务] 取消订单:', orderId);
return { orderId, cancelled: true };
}
},
inventory: {
reserve: async (items) => {
console.log('[库存服务] 预留库存:', items);
// 模拟库存不足
if (items[0].quantity > 100) {
throw new Error('库存不足');
}
return { reservationId: 'RSV_' + Date.now(), items };
},
release: async (reservationId) => {
console.log('[库存服务] 释放库存:', reservationId);
return { reservationId, released: true };
}
},
payment: {
charge: async (amount, source) => {
console.log('[支付服务] 扣款:', { amount, source });
return { chargeId: 'CHG_' + Date.now(), amount, source };
},
refund: async (chargeId) => {
console.log('[支付服务] 退款:', chargeId);
return { chargeId, refunded: true };
}
}
};
async function main() {
console.log('='.repeat(60));
console.log('Saga 分布式事务示例');
console.log('='.repeat(60));
// 初始化 MonSQLize(不连接数据库,仅用于 Saga)
// 显式禁用 cache,使用内存模式
const msq = new MonSQLize({
type: 'mongodb',
config: { uri: 'mongodb://localhost:27017/test' },
cache: false, // 禁用缓存,Saga 使用内存存储
logger: { level: 'info' }
});
// 定义订单 Saga
msq.defineSaga({
name: 'create-order-with-payment',
steps: [
{
name: 'create-order',
execute: async (ctx) => {
const orderData = {
userId: ctx.data.userId,
items: ctx.data.items,
amount: ctx.data.amount
};
const result = await mockServices.orders.create(orderData);
ctx.set('orderId', result.orderId);
return result;
},
compensate: async (ctx) => {
const orderId = ctx.get('orderId');
await mockServices.orders.cancel(orderId);
}
},
{
name: 'reserve-inventory',
execute: async (ctx) => {
const result = await mockServices.inventory.reserve(ctx.data.items);
ctx.set('reservationId', result.reservationId);
return result;
},
compensate: async (ctx) => {
const reservationId = ctx.get('reservationId');
await mockServices.inventory.release(reservationId);
}
},
{
name: 'charge-payment',
execute: async (ctx) => {
const result = await mockServices.payment.charge(
ctx.data.amount,
ctx.data.paymentSource
);
ctx.set('chargeId', result.chargeId);
return result;
},
compensate: async (ctx) => {
const chargeId = ctx.get('chargeId');
await mockServices.payment.refund(chargeId);
}
}
]
});
// 场景1:成功执行
console.log('\n场景1:正常订单(应该成功)');
console.log('-'.repeat(60));
try {
const result = await msq.executeSaga('create-order-with-payment', {
userId: 'user123',
items: [{ sku: 'SKU123', quantity: 2, price: 50 }],
amount: 100,
paymentSource: 'card_visa'
});
console.log('\n✅ Saga 执行结果:');
console.log(JSON.stringify(result, null, 2));
} catch (error) {
console.error('❌ 错误:', error.message);
}
// 场景2:库存不足,触发补偿
console.log('\n\n场景2:库存不足(应该触发补偿)');
console.log('-'.repeat(60));
try {
const result = await msq.executeSaga('create-order-with-payment', {
userId: 'user456',
items: [{ sku: 'SKU456', quantity: 200, price: 50 }], // 库存不足
amount: 10000,
paymentSource: 'card_mastercard'
});
console.log('\n⚠️ Saga 执行结果:');
console.log(JSON.stringify(result, null, 2));
} catch (error) {
console.error('❌ 错误:', error.message);
}
// 查看统计
console.log('\n\n统计信息');
console.log('-'.repeat(60));
const stats = msq.getSagaStats();
console.log(JSON.stringify(stats, null, 2));
console.log('\n' + '='.repeat(60));
console.log('示例完成');
console.log('='.repeat(60));
}
// 运行示例
if (require.main === module) {
main().catch(console.error);
}
module.exports = { main };