彻底修复 lewan 自动发货问题-8-8
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
isKuaishouCloudTask,
|
||||
maskPhone,
|
||||
normalizeKuaishouCloudFlow,
|
||||
normalizeStringArray,
|
||||
resolveKuaishouCloudBindUrlExpiresAt,
|
||||
type JsonObject,
|
||||
} from './domain.js'
|
||||
@@ -123,7 +124,16 @@ export async function prepareKuaishouCloudFulfillmentTask(task: TaskRow, options
|
||||
})
|
||||
}
|
||||
|
||||
const selectedCloud = await selectCloudtentaclesSourceForFulfillment(flow)
|
||||
const excludedSourceKeys = normalizeStringArray(options.excludedSourceKeys)
|
||||
const sourceSelectionAttempts = normalizeStringArray(options.sourceSelectionAttempts)
|
||||
const sourceCandidateCount = new Set(
|
||||
normalizeStringArray([...flow.binding.cloudSourceKeys, flow.binding.resolvedSourceKey]),
|
||||
).size
|
||||
const selectedCloud = await selectCloudtentaclesSourceForFulfillment({
|
||||
...flow,
|
||||
excludedSourceKeys,
|
||||
})
|
||||
let retriedOnAnotherSource = false
|
||||
try {
|
||||
const cloudContext = selectedCloud.context
|
||||
const [knapsack, skuList] = await Promise.all([
|
||||
@@ -277,7 +287,10 @@ export async function prepareKuaishouCloudFulfillmentTask(task: TaskRow, options
|
||||
purchasedCount: 0,
|
||||
})),
|
||||
resolvedByName: resolvedBinding.resolvedByName,
|
||||
accountSelection: buildCloudtentaclesSourceSelectionEventDetail(selectedCloud),
|
||||
accountSelection: {
|
||||
...buildCloudtentaclesSourceSelectionEventDetail(selectedCloud),
|
||||
attemptedSourceKeys: [...sourceSelectionAttempts, selectedCloud.sourceKey],
|
||||
},
|
||||
defaultRoleName: defaultRoleSnapshot.defaultName,
|
||||
defaultRoleId: defaultRoleSnapshot.defaultRid,
|
||||
defaultRoleCaptureStatus: defaultRoleSnapshot.defaultCaptureStatus,
|
||||
@@ -293,11 +306,43 @@ export async function prepareKuaishouCloudFulfillmentTask(task: TaskRow, options
|
||||
flow: normalizeKuaishouCloudFlow(nextContext.kuaishouCloudFulfillment),
|
||||
previousVnRelease,
|
||||
}
|
||||
} catch (error) {
|
||||
// Before a VN exists, account-scoped failures are safe to retry on another
|
||||
// candidate. Once a VN is acquired, switching accounts would orphan it.
|
||||
if (
|
||||
flow.binding.vnId <= 0 &&
|
||||
isRetryableCloudtentaclesSourceError(error) &&
|
||||
excludedSourceKeys.length + 1 < sourceCandidateCount
|
||||
) {
|
||||
retriedOnAnotherSource = true
|
||||
selectedCloud.release()
|
||||
return prepareKuaishouCloudFulfillmentTask(task, {
|
||||
...options,
|
||||
excludedSourceKeys: [...excludedSourceKeys, selectedCloud.sourceKey],
|
||||
sourceSelectionAttempts: [...sourceSelectionAttempts, selectedCloud.sourceKey],
|
||||
})
|
||||
}
|
||||
throw error
|
||||
} finally {
|
||||
selectedCloud.release()
|
||||
if (!retriedOnAnotherSource) {
|
||||
selectedCloud.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isRetryableCloudtentaclesSourceError(error: unknown) {
|
||||
const current = error && typeof error === 'object' ? error as JsonObject : {}
|
||||
const code = String(current.errorCode || current.code || '').trim()
|
||||
return (
|
||||
code === 'cloudtentacles_vn_quota_cooldown' ||
|
||||
(code === 'cloudtentacles_vn_appoint_failed' && String(current.message || '').trim().includes('最多同时占用')) ||
|
||||
code === 'cloudtentacles_vn_list_failed' ||
|
||||
code === 'cloudtentacles_sku_list_failed' ||
|
||||
code === 'cloudtentacles_knapsack_failed' ||
|
||||
code === 'cloudtentacles_asset_failed'
|
||||
)
|
||||
}
|
||||
|
||||
/** 旧虚拟号 best-effort 释放:已被回收/权限不足时不算失败 */
|
||||
async function tryReleasePreviousVirtualNumber({
|
||||
task,
|
||||
|
||||
Reference in New Issue
Block a user