fix: auth scheduler env vars, concurrency and browser stability
This commit is contained in:
20
docs/outcomes/FixAuthSchedulerEnvVars.md
Normal file
20
docs/outcomes/FixAuthSchedulerEnvVars.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Outcome - Fix Auth Scheduler Env Vars
|
||||
|
||||
## Summary
|
||||
Successfully fixed the environment variable loading issue in the authentication scheduler and updated the frequency configuration to support minutes.
|
||||
|
||||
## Changes
|
||||
- **Refactored Scheduler Logic:**
|
||||
- Updated `src/lib/server/scheduler.ts` to use `$env/dynamic/private` for reliable environment variable access.
|
||||
- Changed configuration from `intervalHours` to `intervalMinutes`.
|
||||
- Updated `startScheduler` to calculate interval in milliseconds based on minutes.
|
||||
- **Updated Documentation:**
|
||||
- Updated `src/hooks.server.ts` JSDoc to reflect the new configuration.
|
||||
- **Updated Configuration:**
|
||||
- Updated `.env.local` to set `AUTH_SCHEDULER_INTERVAL_MINUTES=5`.
|
||||
- **Verified Tests:**
|
||||
- Updated `src/tests/scheduler.spec.ts` to mock `$env/dynamic/private` and verify the new logic.
|
||||
- All tests passed.
|
||||
|
||||
## Feature Branch
|
||||
`feature/FixAuthSchedulerEnvVars`
|
||||
21
docs/outcomes/FixSchedulerConcurrencyAndBrowser.md
Normal file
21
docs/outcomes/FixSchedulerConcurrencyAndBrowser.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Outcome - Fix Scheduler Concurrency and Browser Stability
|
||||
|
||||
## Summary
|
||||
Successfully implemented fixes for the scheduler concurrency issues and browser instability.
|
||||
|
||||
## Changes
|
||||
- **Scheduler Configuration Validation:**
|
||||
- Updated `src/lib/server/scheduler.ts` to validate `intervalMinutes`.
|
||||
- Added a check for `NaN` and a minimum interval of 15 minutes.
|
||||
- Defaults to 720 minutes if the configuration is invalid.
|
||||
- **Resource Cleanup:**
|
||||
- Refactored `renewInstagramAuth` in `src/lib/server/scheduler.ts` to use a `finally` block for closing `page` and `context`.
|
||||
- Ensures resources are released even if an error occurs during renewal.
|
||||
- **Robust Browser Management:**
|
||||
- Updated `src/lib/server/browser.ts` to check `browser.isConnected()`.
|
||||
- Automatically re-initializes the browser if it is disconnected or crashed.
|
||||
|
||||
## Verification
|
||||
- The scheduler will now default to a safe interval if misconfigured, preventing console spam.
|
||||
- Browser crashes will be automatically recovered from on the next scheduler run.
|
||||
- Resource leaks from failed renewal attempts are prevented.
|
||||
89
docs/plans/FixSchedulerConcurrencyAndBrowser.md
Normal file
89
docs/plans/FixSchedulerConcurrencyAndBrowser.md
Normal 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;
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user