@flowlab/all
Version:
A cool library focusing on handling various flows
148 lines (132 loc) • 6.47 kB
text/typescript
// ---------- 模拟的外部服务 ----------
interface UserInfo { userId: string; email: string; vipLevel: 'VIP' | 'Normal'; }
interface ProductInfo { productId: string; price: number; stock: number; }
interface Order { orderId: string; userId: string; productId: string; finalPrice: number; status: 'Created' | 'Failed'; }
// 模拟用户服务 (可能失败)
async function fetchUserService(userId: string): Promise<UserInfo> {
console.log(`[服务] 获取用户 ${userId} 信息...`);
await new Promise(res => setTimeout(res, 50)); // 模拟网络延迟
if (Math.random() < 0.1) { // 10% 概率失败
throw new Error('用户服务暂时不可用');
}
return { userId, email: `${userId}@test.com`, vipLevel: Math.random() > 0.5 ? 'VIP' : 'Normal' };
}
// 模拟商品服务 (可能失败)
async function fetchProductService(productId: string): Promise<ProductInfo> {
console.log(`[服务] 获取商品 ${productId} 信息...`);
await new Promise(res => setTimeout(res, 60)); // 模拟网络延迟
if (Math.random() < 0.1) { // 10% 概率失败
throw new Error('商品服务暂时不可用');
}
const stock = Math.floor(Math.random() * 5); // 0-4 的随机库存
return { productId, price: 100, stock };
}
// 模拟订单服务 (可能失败)
async function createOrderService(userId: string, productId: string, price: number): Promise<{ orderId: string }> {
console.log(`[服务] 正在为用户 ${userId} 创建商品 ${productId} 的订单,价格: ${price}...`);
await new Promise(res => setTimeout(res, 70));
if (Math.random() < 0.05) { // 5% 概率失败
throw new Error('订单服务创建失败');
}
return { orderId: `order-${Date.now()}` };
}
// 模拟邮件服务
async function sendEmailService(email: string, subject: string, body: string): Promise<void> {
console.log(`[服务] 发送邮件给 ${email} | 主题: ${subject} | 内容: ${body}`);
await new Promise(res => setTimeout(res, 40));
// 假设邮件发送总能成功
}
// ---------- 带重试的辅助函数 ----------
async function retry<T>(fn: () => Promise<T>, retries = 2, delayMs = 100): Promise<T> {
let lastError: Error | undefined;
for (let i = 0; i <= retries; i++) {
try {
return await fn(); // 尝试执行
} catch (error: any) {
lastError = error; // 记录错误
console.warn(`[重试] 第 ${i + 1} 次尝试失败: ${error.message}`);
if (i < retries) {
await new Promise(res => setTimeout(res, delayMs * Math.pow(2, i))); // 指数退避等待
}
}
}
console.error(`[重试] 达到最大重试次数后仍然失败。`);
throw lastError; // 抛出最后一次的错误
}
// ---------- 主要业务流程函数 ----------
async function processOrderRequest(request: { userId: string; productId: string }) {
console.log(`\n--- 开始处理订单请求: 用户 ${request.userId}, 商品 ${request.productId} ---`);
let userInfo: UserInfo | undefined;
let productInfo: ProductInfo | undefined;
let finalPrice = 0;
let orderResult: { orderId: string } | undefined;
let orderStatus: 'Success' | 'Failed' = 'Failed'; // 默认失败
let failureReason = '';
try {
// 1 & 2: 并行获取用户信息和商品信息 (带重试)
// 注意:实际项目中可能需要更健壮的并行控制和错误处理库 (如 Promise.allSettled)
[userInfo, productInfo] = await Promise.all([
retry(() => fetchUserService(request.userId)),
retry(() => fetchProductService(request.productId))
]);
console.log('[流程] 用户和商品信息获取成功。');
// 3. 检查库存
if (productInfo.stock <= 0) {
failureReason = '商品库存不足';
console.warn(`[流程] ${failureReason}`);
throw new Error(failureReason); // 中断流程
}
console.log(`[流程] 库存检查通过 (${productInfo.stock})。`);
// 4. 计算价格
finalPrice = productInfo.price;
if (userInfo.vipLevel === 'VIP') {
finalPrice = finalPrice * 0.9; // VIP 九折
console.log(`[流程] 用户是 VIP,应用折扣。最终价格: ${finalPrice}`);
} else {
console.log(`[流程] 用户非 VIP。最终价格: ${finalPrice}`);
}
// 5. 创建订单 (带重试)
orderResult = await retry(() => createOrderService(userInfo!.userId, productInfo!.productId, finalPrice), 1, 200); // 重试1次
orderStatus = 'Success';
console.log(`[流程] 订单创建成功: ${orderResult.orderId}`);
} catch (error: any) {
console.error(`[流程] 处理订单时发生错误: ${error.message}`);
if (!failureReason) { // 如果没有指定具体业务失败原因,则使用捕获到的错误
failureReason = error.message;
}
// 即使失败,也需要尝试发送通知,所以错误在这里被捕获
}
// 6. 发送通知 (无论成功失败都尝试发送)
if (userInfo) { // 只有获取到用户信息才能发送邮件
const subject = orderStatus === 'Success' ? '订单创建成功' : '订单创建失败';
const body = orderStatus === 'Success'
? `您的订单 ${orderResult?.orderId} 已成功创建,商品 ${request.productId},价格 ${finalPrice}。`
: `抱歉,您的订单 (商品 ${request.productId}) 创建失败。原因: ${failureReason}`;
try {
await sendEmailService(userInfo.email, subject, body);
console.log('[流程] 通知邮件已发送。');
} catch (emailError: any) {
console.error(`[流程] 发送通知邮件失败: ${emailError.message}`);
// 记录发送邮件失败,但通常不影响主流程结果
}
} else {
console.warn('[流程] 未能获取用户信息,无法发送通知邮件。');
}
console.log(`--- 订单请求处理结束,最终状态: ${orderStatus} ---`);
// 返回一个包含最终状态和相关信息的结果对象
return {
success: orderStatus === 'Success',
orderId: orderResult?.orderId,
userId: request.userId,
productId: request.productId,
finalPrice: orderStatus === 'Success' ? finalPrice : undefined,
reason: orderStatus !== 'Success' ? failureReason : undefined,
};
}
// ---------- 执行示例 ----------
async function runExample() {
await processOrderRequest({ userId: 'user1', productId: 'productA' });
// 可以再调用几次,观察随机失败和库存不足的情况
// await processOrderRequest({ userId: 'user2', productId: 'productB' });
}
runExample();