fix: auth scheduler env vars, concurrency and browser stability

This commit is contained in:
Giancarmine Salucci
2025-12-21 02:15:22 +01:00
parent 9357bd483a
commit 342a8eb259
9 changed files with 420 additions and 79 deletions

View File

@@ -0,0 +1,89 @@
# 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`
```typescript
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`
```typescript
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;
}
```