feat: 添加过期步骤消息处理,忽略自动运行中已完成的步骤错误和完成消息
This commit is contained in:
@@ -167,6 +167,25 @@
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isStaleAutoRunStepMessage(step, state = {}) {
|
||||||
|
if (typeof isAutoRunLockedState !== 'function' || !isAutoRunLockedState(state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const normalizedStep = Number(step);
|
||||||
|
if (!Number.isInteger(normalizedStep) || normalizedStep <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const currentStatus = String(state?.stepStatuses?.[normalizedStep] || '').trim();
|
||||||
|
if (currentStatus === 'running') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const currentStep = Number(state?.currentStep) || 0;
|
||||||
|
if (currentStep > 0 && normalizedStep !== currentStep) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ['completed', 'manual_completed', 'skipped', 'failed', 'stopped'].includes(currentStatus);
|
||||||
|
}
|
||||||
|
|
||||||
function resolveSignupPhonePayload(payload = {}) {
|
function resolveSignupPhonePayload(payload = {}) {
|
||||||
const directPhone = String(
|
const directPhone = String(
|
||||||
payload?.signupPhoneNumber
|
payload?.signupPhoneNumber
|
||||||
@@ -540,6 +559,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'STEP_COMPLETE': {
|
case 'STEP_COMPLETE': {
|
||||||
|
const currentState = await getState();
|
||||||
|
if (isStaleAutoRunStepMessage(message.step, currentState)) {
|
||||||
|
await addLog(`自动运行:忽略过期的步骤 ${message.step} 完成消息,当前流程已在步骤 ${currentState.currentStep || '未知'}。`, 'warn', { step: message.step });
|
||||||
|
return { ok: true, ignored: true };
|
||||||
|
}
|
||||||
if (getStopRequested()) {
|
if (getStopRequested()) {
|
||||||
await setStepStatus(message.step, 'stopped');
|
await setStepStatus(message.step, 'stopped');
|
||||||
await appendManualAccountRunRecordIfNeeded(`step${message.step}_stopped`, null, '流程已被用户停止。');
|
await appendManualAccountRunRecordIfNeeded(`step${message.step}_stopped`, null, '流程已被用户停止。');
|
||||||
@@ -582,6 +606,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'STEP_ERROR': {
|
case 'STEP_ERROR': {
|
||||||
|
const staleCheckState = await getState();
|
||||||
|
if (isStaleAutoRunStepMessage(message.step, staleCheckState)) {
|
||||||
|
await addLog(`自动运行:忽略过期的步骤 ${message.step} 失败消息,当前流程已在步骤 ${staleCheckState.currentStep || '未知'}。原始错误:${message.error || '未知错误'}`, 'warn', { step: message.step });
|
||||||
|
return { ok: true, ignored: true };
|
||||||
|
}
|
||||||
if (typeof isCloudflareSecurityBlockedError === 'function' && isCloudflareSecurityBlockedError(message.error)) {
|
if (typeof isCloudflareSecurityBlockedError === 'function' && isCloudflareSecurityBlockedError(message.error)) {
|
||||||
const userMessage = typeof handleCloudflareSecurityBlocked === 'function'
|
const userMessage = typeof handleCloudflareSecurityBlocked === 'function'
|
||||||
? await handleCloudflareSecurityBlocked(message.error)
|
? await handleCloudflareSecurityBlocked(message.error)
|
||||||
|
|||||||
@@ -23,13 +23,17 @@ function createRouter(overrides = {}) {
|
|||||||
securityBlocks: [],
|
securityBlocks: [],
|
||||||
invalidations: [],
|
invalidations: [],
|
||||||
executedSteps: [],
|
executedSteps: [],
|
||||||
|
accountRecords: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const router = api.createMessageRouter({
|
const router = api.createMessageRouter({
|
||||||
addLog: async (message, level, options = {}) => {
|
addLog: async (message, level, options = {}) => {
|
||||||
events.logs.push({ message, level, step: options.step, stepKey: options.stepKey });
|
events.logs.push({ message, level, step: options.step, stepKey: options.stepKey });
|
||||||
},
|
},
|
||||||
appendAccountRunRecord: async () => null,
|
appendAccountRunRecord: overrides.appendAccountRunRecord || (async (status, state, reason) => {
|
||||||
|
events.accountRecords.push({ status, state, reason });
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
batchUpdateLuckmailPurchases: async () => {},
|
batchUpdateLuckmailPurchases: async () => {},
|
||||||
buildLocalhostCleanupPrefix: () => '',
|
buildLocalhostCleanupPrefix: () => '',
|
||||||
buildLuckmailSessionSettingsPayload: () => ({}),
|
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||||
@@ -89,7 +93,7 @@ function createRouter(overrides = {}) {
|
|||||||
events.invalidations.push({ step, options });
|
events.invalidations.push({ step, options });
|
||||||
},
|
},
|
||||||
isCloudflareSecurityBlockedError: overrides.isCloudflareSecurityBlockedError || ((error) => /^CF_SECURITY_BLOCKED::/.test(typeof error === 'string' ? error : error?.message || '')),
|
isCloudflareSecurityBlockedError: overrides.isCloudflareSecurityBlockedError || ((error) => /^CF_SECURITY_BLOCKED::/.test(typeof error === 'string' ? error : error?.message || '')),
|
||||||
isAutoRunLockedState: () => false,
|
isAutoRunLockedState: overrides.isAutoRunLockedState || (() => false),
|
||||||
isHotmailProvider: () => false,
|
isHotmailProvider: () => false,
|
||||||
isLocalhostOAuthCallbackUrl: () => true,
|
isLocalhostOAuthCallbackUrl: () => true,
|
||||||
isLuckmailProvider: () => false,
|
isLuckmailProvider: () => false,
|
||||||
@@ -562,3 +566,59 @@ test('message router refreshes GPC balance through explicit sidepanel message',
|
|||||||
assert.equal(events.balanceRefreshes[0].state.gopayHelperApiKey, 'payload_api_key');
|
assert.equal(events.balanceRefreshes[0].state.gopayHelperApiKey, 'payload_api_key');
|
||||||
assert.deepStrictEqual(events.balanceRefreshes[0].options, { reason: 'manual' });
|
assert.deepStrictEqual(events.balanceRefreshes[0].options, { reason: 'manual' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('message router ignores stale step 2 errors while auto-run is already on a later step', async () => {
|
||||||
|
const { router, events } = createRouter({
|
||||||
|
state: {
|
||||||
|
autoRunning: true,
|
||||||
|
autoRunPhase: 'running',
|
||||||
|
currentStep: 6,
|
||||||
|
stepStatuses: {
|
||||||
|
2: 'completed',
|
||||||
|
6: 'running',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isAutoRunLockedState: (state) => Boolean(state?.autoRunning) && state?.autoRunPhase === 'running',
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await router.handleMessage({
|
||||||
|
type: 'STEP_ERROR',
|
||||||
|
step: 2,
|
||||||
|
error: '步骤 2:旧页面异步失败,不应覆盖当前第 6 步记录。',
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(response, { ok: true, ignored: true });
|
||||||
|
assert.deepStrictEqual(events.stepStatuses, []);
|
||||||
|
assert.deepStrictEqual(events.notifyErrors, []);
|
||||||
|
assert.deepStrictEqual(events.accountRecords, []);
|
||||||
|
assert.equal(events.logs.some(({ message }) => /忽略过期的步骤 2 失败消息/.test(message)), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('message router ignores stale step 2 completion while auto-run is already on a later step', async () => {
|
||||||
|
const { router, events } = createRouter({
|
||||||
|
state: {
|
||||||
|
autoRunning: true,
|
||||||
|
autoRunPhase: 'running',
|
||||||
|
currentStep: 6,
|
||||||
|
stepStatuses: {
|
||||||
|
2: 'completed',
|
||||||
|
6: 'running',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isAutoRunLockedState: (state) => Boolean(state?.autoRunning) && state?.autoRunPhase === 'running',
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await router.handleMessage({
|
||||||
|
type: 'STEP_COMPLETE',
|
||||||
|
step: 2,
|
||||||
|
payload: {
|
||||||
|
email: 'late@example.com',
|
||||||
|
},
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
assert.deepStrictEqual(response, { ok: true, ignored: true });
|
||||||
|
assert.deepStrictEqual(events.stepStatuses, []);
|
||||||
|
assert.deepStrictEqual(events.notifyCompletions, []);
|
||||||
|
assert.deepStrictEqual(events.emailStates, []);
|
||||||
|
assert.equal(events.logs.some(({ message }) => /忽略过期的步骤 2 完成消息/.test(message)), true);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user