(source, message, options = {})
| 547 | } |
| 548 | |
| 549 | async function sendToContentScriptResilient(source, message, options = {}) { |
| 550 | const { timeoutMs = 30000, retryDelayMs = 600, logMessage = '' } = options; |
| 551 | const start = Date.now(); |
| 552 | let lastError = null; |
| 553 | let logged = false; |
| 554 | let attempt = 0; |
| 555 | |
| 556 | while (Date.now() - start < timeoutMs) { |
| 557 | throwIfStopped(); |
| 558 | attempt += 1; |
| 559 | |
| 560 | try { |
| 561 | return await sendToContentScript(source, message); |
| 562 | } catch (err) { |
| 563 | const retryable = isRetryableContentScriptTransportError(err); |
| 564 | if (!retryable) { |
| 565 | throw err; |
| 566 | } |
| 567 | |
| 568 | lastError = err; |
| 569 | if (logMessage && !logged) { |
| 570 | await addLog(logMessage, 'warn'); |
| 571 | logged = true; |
| 572 | } |
| 573 | |
| 574 | await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | throw lastError || new Error(`等待 ${getSourceLabel(source)} 重新就绪超时。`); |
| 579 | } |
| 580 | |
| 581 | async function sendToMailContentScriptResilient(mail, message, options = {}) { |
| 582 | const { timeoutMs = 45000, maxRecoveryAttempts = 2 } = options; |
no test coverage detected