Files
insta-recipe/docs/plans/FixSchedulerConcurrencyAndBrowser.md
2025-12-21 02:15:22 +01:00

3.9 KiB

Execution Plan: Fix Scheduler Concurrency and Browser Stability

Context

The application is experiencing two related issues with the Instagram authentication scheduler:

  1. Console Spam: "Auth renewal already in progress" is logged repeatedly. This indicates the scheduler is triggering new renewal attempts while a previous one is still active (or perceived as active). This is likely caused by an invalid or extremely short interval configuration (e.g., NaN resulting from parsing failure).
  2. Browser Instability: "Target page, context or browser has been closed" errors. This occurs when the scheduler attempts to use a cached Playwright browser instance that has crashed or disconnected.

Goal

Ensure the authentication scheduler runs reliably at the configured interval without overlapping executions, and make the browser instance management robust against crashes.

Exception to workflow

Do not create a dedicated branch. It's a fix on a new feature.

Proposed Solution

Story 1: Fix Scheduler Configuration and Resource Cleanup

Objective: Prevent rapid-fire execution of the scheduler and ensure browser resources are cleaned up properly even when errors occur.

Changes:

  1. Validate Configuration: In src/lib/server/scheduler.ts, update getConfig() to strictly validate intervalMinutes.
    • Handle NaN (parsing errors).
    • Enforce a minimum interval (e.g., 15 minutes) to prevent spamming.
    • Default to 720 minutes if invalid.
  2. Improve Resource Management: Refactor renewInstagramAuth to ensure page and context are closed in a finally block (or nested try/finally), preventing resource leaks if an error occurs during the renewal process.

Verification:

  • Set AUTH_SCHEDULER_INTERVAL_MINUTES to an invalid value (e.g., "abc") and verify it defaults to 720.
  • Verify that setInterval is called with a valid duration.

Story 2: Robust Browser Lifecycle Management

Objective: Ensure the application automatically recovers from browser crashes by detecting disconnected instances.

Changes:

  1. Check Connection Status: In src/lib/server/browser.ts, update getBrowser() to check browser.isConnected().
  2. Auto-Recovery: If the cached browser instance is not connected:
    • Log a warning.
    • Attempt to close the dead instance (swallowing errors).
    • Re-initialize a new browser instance.

Verification:

  • Simulate a browser crash (e.g., by manually killing the chrome process if possible, or mocking isConnected to return false).
  • Verify that the next call to getBrowser() creates a new instance instead of throwing.

Implementation Details

src/lib/server/scheduler.ts

function getConfig(): SchedulerConfig {
    const enabled = env.AUTH_SCHEDULER_ENABLED === 'true';
    let intervalMinutes = parseInt(env.AUTH_SCHEDULER_INTERVAL_MINUTES || '720', 10);

    if (isNaN(intervalMinutes) || intervalMinutes < 15) {
        console.warn(`[Scheduler] Invalid or too short interval '${env.AUTH_SCHEDULER_INTERVAL_MINUTES}'. Defaulting to 720 minutes.`);
        intervalMinutes = 720;
    }

    return { enabled, intervalMinutes };
}

// In renewInstagramAuth:
let context = null;
let page = null;
try {
    // ... setup ...
    context = await browser.newContext(...);
    page = await context.newPage();
    // ... logic ...
} catch (e) {
    // ... error handling ...
} finally {
    if (page) await page.close().catch(() => {});
    if (context) await context.close().catch(() => {});
    state.isRenewing = false;
}

src/lib/server/browser.ts

export async function getBrowser(): Promise<Browser> {
    if (!browser || !browser.isConnected()) {
        if (browser) {
            console.warn('Browser is disconnected. Re-initializing...');
            try { await browser.close(); } catch (e) { /* ignore */ }
        }
        return initializeBrowser();
    }
    return browser;
}