|
|
@@ -2805,7 +2805,11 @@ async function handleMessage(message, sender) {
|
|
|
await setPersistentSettings({ emailPrefix: message.payload.emailPrefix });
|
|
|
await setState({ emailPrefix: message.payload.emailPrefix });
|
|
|
}
|
|
|
- await executeStep(step);
|
|
|
+ if (doesStepUseCompletionSignal(step)) {
|
|
|
+ await executeStepViaCompletionSignal(step);
|
|
|
+ } else {
|
|
|
+ await executeStep(step);
|
|
|
+ }
|
|
|
return { ok: true };
|
|
|
}
|
|
|
|
|
|
@@ -3083,6 +3087,7 @@ const stepWaiters = new Map();
|
|
|
let resumeWaiter = null;
|
|
|
const AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS = 120000;
|
|
|
const AUTO_RUN_BACKGROUND_COMPLETED_STEPS = new Set([4, 7, 8]);
|
|
|
+const STEP_COMPLETION_SIGNAL_STEPS = new Set([1, 2, 3, 5, 6, 9]);
|
|
|
|
|
|
function waitForStepComplete(step, timeoutMs = 120000) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
@@ -3104,6 +3109,10 @@ function waitForStepComplete(step, timeoutMs = 120000) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+function doesStepUseCompletionSignal(step) {
|
|
|
+ return STEP_COMPLETION_SIGNAL_STEPS.has(step);
|
|
|
+}
|
|
|
+
|
|
|
function notifyStepComplete(step, payload) {
|
|
|
const waiter = stepWaiters.get(step);
|
|
|
console.log(LOG_PREFIX, `[notifyStepComplete] step ${step}, hasWaiter=${Boolean(waiter)}`);
|
|
|
@@ -3129,6 +3138,66 @@ async function completeStepFromBackground(step, payload = {}) {
|
|
|
notifyStepComplete(step, payload);
|
|
|
}
|
|
|
|
|
|
+async function finalizeDeferredStepExecutionError(step, error) {
|
|
|
+ const latestState = await getState();
|
|
|
+ const currentStatus = latestState.stepStatuses?.[step];
|
|
|
+ if (currentStatus === 'completed' || currentStatus === 'failed' || currentStatus === 'stopped') {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isStopError(error)) {
|
|
|
+ await setStepStatus(step, 'stopped');
|
|
|
+ await addLog(`步骤 ${step} 已被用户停止`, 'warn');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ await setStepStatus(step, 'failed');
|
|
|
+ await addLog(`步骤 ${step} 失败:${getErrorMessage(error)}`, 'error');
|
|
|
+}
|
|
|
+
|
|
|
+async function executeStepViaCompletionSignal(step, timeoutMs = AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS) {
|
|
|
+ const completionResultPromise = waitForStepComplete(step, timeoutMs).then(
|
|
|
+ payload => ({ ok: true, payload }),
|
|
|
+ error => ({ ok: false, error }),
|
|
|
+ );
|
|
|
+
|
|
|
+ let executeError = null;
|
|
|
+ try {
|
|
|
+ await executeStep(step, { deferRetryableTransportError: true });
|
|
|
+ } catch (err) {
|
|
|
+ executeError = err;
|
|
|
+ if (isStopError(err) || !isRetryableContentScriptTransportError(err)) {
|
|
|
+ notifyStepError(step, getErrorMessage(err));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const completionResult = await completionResultPromise;
|
|
|
+ if (completionResult.ok) {
|
|
|
+ if (executeError) {
|
|
|
+ console.warn(
|
|
|
+ LOG_PREFIX,
|
|
|
+ `[executeStepViaCompletionSignal] step ${step} completed after deferred execute error: ${getErrorMessage(executeError)}`
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return completionResult.payload;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (executeError && isRetryableContentScriptTransportError(executeError)) {
|
|
|
+ const completionMessage = getErrorMessage(completionResult.error);
|
|
|
+ if (/等待超时/.test(completionMessage)) {
|
|
|
+ await finalizeDeferredStepExecutionError(step, executeError);
|
|
|
+ throw executeError;
|
|
|
+ }
|
|
|
+ throw completionResult.error;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (executeError) {
|
|
|
+ throw executeError;
|
|
|
+ }
|
|
|
+
|
|
|
+ throw completionResult.error;
|
|
|
+}
|
|
|
+
|
|
|
async function waitForRunningStepsToFinish(payload = {}) {
|
|
|
let currentState = await getState();
|
|
|
let runningSteps = getRunningSteps(currentState.stepStatuses);
|
|
|
@@ -3204,7 +3273,8 @@ async function requestStop(options = {}) {
|
|
|
// Step Execution
|
|
|
// ============================================================
|
|
|
|
|
|
-async function executeStep(step) {
|
|
|
+async function executeStep(step, options = {}) {
|
|
|
+ const { deferRetryableTransportError = false } = options;
|
|
|
console.log(LOG_PREFIX, `Executing step ${step}`);
|
|
|
throwIfStopped();
|
|
|
await setStepStatus(step, 'running');
|
|
|
@@ -3238,8 +3308,15 @@ async function executeStep(step) {
|
|
|
await addLog(`步骤 ${step} 已被用户停止`, 'warn');
|
|
|
throw err;
|
|
|
}
|
|
|
- await setStepStatus(step, 'failed');
|
|
|
- await addLog(`步骤 ${step} 失败:${err.message}`, 'error');
|
|
|
+ if (!(deferRetryableTransportError && doesStepUseCompletionSignal(step) && isRetryableContentScriptTransportError(err))) {
|
|
|
+ await setStepStatus(step, 'failed');
|
|
|
+ await addLog(`步骤 ${step} 失败:${err.message}`, 'error');
|
|
|
+ } else {
|
|
|
+ console.warn(
|
|
|
+ LOG_PREFIX,
|
|
|
+ `[executeStep] deferring retryable transport error for step ${step}: ${getErrorMessage(err)}`
|
|
|
+ );
|
|
|
+ }
|
|
|
throw err;
|
|
|
}
|
|
|
}
|
|
|
@@ -3266,27 +3343,12 @@ async function executeStepAndWait(step, delayAfter = 2000) {
|
|
|
await executeStep(step);
|
|
|
const latestState = await getState();
|
|
|
await addLog(`自动运行:步骤 ${step} 已执行返回,当前状态为 ${latestState.stepStatuses?.[step] || 'pending'},准备继续后续步骤。`, 'info');
|
|
|
- } else {
|
|
|
+ } else if (doesStepUseCompletionSignal(step)) {
|
|
|
await addLog(`自动运行:步骤 ${step} 已发起,正在等待完成信号(超时 ${AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS / 1000} 秒)。`, 'info');
|
|
|
- const completionResultPromise = waitForStepComplete(step, AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS).then(
|
|
|
- payload => ({ ok: true, payload }),
|
|
|
- error => ({ ok: false, error }),
|
|
|
- );
|
|
|
-
|
|
|
- try {
|
|
|
- await executeStep(step);
|
|
|
- } catch (err) {
|
|
|
- notifyStepError(step, getErrorMessage(err));
|
|
|
- await completionResultPromise;
|
|
|
- throw err;
|
|
|
- }
|
|
|
-
|
|
|
- const completionResult = await completionResultPromise;
|
|
|
- if (!completionResult.ok) {
|
|
|
- throw completionResult.error;
|
|
|
- }
|
|
|
-
|
|
|
+ await executeStepViaCompletionSignal(step, AUTO_RUN_SIGNAL_COMPLETION_TIMEOUT_MS);
|
|
|
await addLog(`自动运行:步骤 ${step} 已收到完成信号,准备继续后续步骤。`, 'info');
|
|
|
+ } else {
|
|
|
+ await executeStep(step);
|
|
|
}
|
|
|
|
|
|
// Extra delay for page transitions / DOM updates
|