Merge branch 'codex/wuyongjie-bom-rearchive-batch-20260804' into codex/release-bom-rearchive-xuxiake-20260804

This commit is contained in:
WuYongJie 2026-08-04 23:45:26 +08:00
commit 0a3bd1969c
5 changed files with 51 additions and 5 deletions

View File

@ -1162,7 +1162,7 @@ describe('BOM 多模态分析器', () => {
)
})
it('最终汇总遇到瞬时网络超时时自动重试一次', async () => {
it('最终汇总遇到网络超时时立即拆分,不重试整批', async () => {
const transportError = new TypeError('socket timed out')
Object.assign(transportError, {
cause: Object.assign(new Error('connect timed out'), {
@ -1175,7 +1175,14 @@ describe('BOM 多模态分析器', () => {
createStreamingResponse(JSON.stringify({
product: { category: '书桌' },
structureGroups: [analyzedStructureGroup()],
skus: [analyzedSku('sku-white'), analyzedSku('sku-black')],
skus: [analyzedSku('sku-white')],
})),
)
.mockResolvedValueOnce(
createStreamingResponse(JSON.stringify({
product: { category: '书桌' },
structureGroups: [analyzedStructureGroup()],
skus: [analyzedSku('sku-black')],
})),
)
@ -1185,7 +1192,7 @@ describe('BOM 多模态分析器', () => {
existingFactSnapshot: createCompleteFactSnapshot(snapshot),
})
expect(fetchSpy).toHaveBeenCalledTimes(2)
expect(fetchSpy).toHaveBeenCalledTimes(3)
expect(output.result.skus).toHaveLength(2)
})

View File

@ -39,4 +39,31 @@ describe('BOM 多模态网关', () => {
expect(fetchSpy).toHaveBeenCalledTimes(1)
expect((cancelReason as Error | undefined)?.name).toBe('TimeoutError')
})
it('规格汇总遇到网络超时时立即交由上层拆分,不白白重试整批', async () => {
const networkTimeout = Object.assign(
new Error('socket timed out'),
{ code: 'ETIMEDOUT' },
)
const fetchSpy = jest.spyOn(global, 'fetch').mockRejectedValue(
networkTimeout,
)
await expect(
callBomCostingMultimodalModel({
config: {
baseUrl: 'https://ai.example.com/v1',
apiKey: 'test-key',
model: 'gpt-5.6-luna',
},
operation: 'SYNTHESIS',
systemPrompt: 'test',
userContent: 'test',
maxTokens: 100,
timeoutMs: 25,
}),
).rejects.toThrow('多模态 BOM 分析超时')
expect(fetchSpy).toHaveBeenCalledTimes(1)
})
})

View File

@ -438,7 +438,7 @@ export async function callBomCostingMultimodalModel(input: {
!(
input.operation === 'SYNTHESIS' &&
!input.retrySynthesisTimeout &&
isDirectMultimodalTimeoutError(error)
isMultimodalTimeoutFailure(error)
)
) {
console.warn('[BOM costing] retrying transient multimodal request', {
@ -506,7 +506,7 @@ export async function callBomCostingMultimodalModel(input: {
!(
input.operation === 'SYNTHESIS' &&
!input.retrySynthesisTimeout &&
isDirectMultimodalTimeoutError(error)
isMultimodalTimeoutFailure(error)
)
) {
console.warn('[BOM costing] retrying transient multimodal request', {

View File

@ -210,6 +210,12 @@ start_pm2_release() {
local worker_command
local worker_timeout
prepare_standalone_runtime "$app_root"
# Read the shared environment before resolving the curl limit. The worker
# command itself sources this file later, but doing it only there leaves the
# already-interpolated --max-time stuck at the 45-minute default.
set -a
source "$SHARED/.env"
set +a
worker_timeout="${BOM_COSTING_WORKER_REQUEST_TIMEOUT_SECONDS:-2700}"
if ! [[ "$worker_timeout" =~ ^[1-9][0-9]*$ ]]; then
worker_timeout=2700

View File

@ -268,6 +268,12 @@ start_pm2_release() {
local worker_command
local worker_timeout
prepare_standalone_runtime "$app_root"
# Read the shared environment before resolving the curl limit. The worker
# command itself sources this file later, but doing it only there leaves the
# already-interpolated --max-time stuck at the 45-minute default.
set -a
source "$SHARED/.env"
set +a
worker_timeout="${BOM_COSTING_WORKER_REQUEST_TIMEOUT_SECONDS:-2700}"
if ! [[ "$worker_timeout" =~ ^[1-9][0-9]*$ ]]; then
worker_timeout=2700