164 lines
5.4 KiB
Markdown
164 lines
5.4 KiB
Markdown
# P0-002: Session Loop Bug (Returned)
|
|
|
|
**Priority:** P0 (Critical)
|
|
**Source Reference:** From SessionLoopBug.md line 4
|
|
**Date Identified:** 2025-11-12
|
|
**Previous Fix Attempt:** Commit 7b77641 - "fix: resolve 401 session refresh loop"
|
|
|
|
## Problem Description
|
|
|
|
The session refresh loop bug has returned. After completing setup and the server restarts, the UI flashes/loops rapidly if you're on the dashboard, agents, or settings pages. Users must manually logout and log back in to stop the loop.
|
|
|
|
## Reproduction Steps
|
|
|
|
1. Complete setup wizard in fresh installation
|
|
2. Click "Restart Server" button (or restart manually via `docker-compose restart server`)
|
|
3. Server goes down, Docker components restart
|
|
4. UI automatically redirects from setup to dashboard
|
|
5. **BUG:** Screen starts flashing/rapid refresh loop
|
|
6. Clicking Logout stops the loop
|
|
7. Logging back in works fine
|
|
|
|
## Root Cause Analysis
|
|
|
|
The issue is in the `SetupCompletionChecker` component which has a dependency array problem in its `useEffect` hook:
|
|
|
|
```typescript
|
|
useEffect(() => {
|
|
const checkSetupStatus = async () => { ... }
|
|
checkSetupStatus();
|
|
const interval = setInterval(checkSetupStatus, 3000);
|
|
return () => clearInterval(interval);
|
|
}, [wasInSetupMode, location.pathname, navigate]); // ← Problem here
|
|
```
|
|
|
|
**Issue:** `wasInSetupMode` is in the dependency array. When it changes from `false` to `true` to `false`, it triggers new effect runs, creating multiple overlapping intervals without properly cleaning up the old ones.
|
|
|
|
**During Docker Restart Sequence:**
|
|
1. Initial render: creates interval 1
|
|
2. Server goes down: can't fetch health, sets `wasInSetupMode`
|
|
3. Effect re-runs: interval 1 still running, creates interval 2
|
|
4. Server comes back: detects not in setup mode
|
|
5. Effect re-runs again: interval 1 & 2 still running, creates interval 3
|
|
6. Result: 3+ intervals all polling every 3 seconds = rapid flashing
|
|
|
|
## Proposed Solution
|
|
|
|
**Option 1: Remove wasInSetupMode from dependencies (Recommended)**
|
|
```typescript
|
|
useEffect(() => {
|
|
let wasInSetup = false;
|
|
|
|
const checkSetupStatus = async () => {
|
|
// Use local wasInSetup variable instead of state dependency
|
|
// ... existing logic using wasInSetup local variable
|
|
};
|
|
|
|
checkSetupStatus();
|
|
const interval = setInterval(checkSetupStatus, 3000);
|
|
return () => clearInterval(interval);
|
|
}, [location.pathname, navigate]); // Only pathname and navigate
|
|
```
|
|
|
|
**Option 2: Add interval guard**
|
|
```typescript
|
|
const [intervalId, setIntervalId] = useState<number | null>(null);
|
|
|
|
useEffect(() => {
|
|
// Clear any existing interval first
|
|
if (intervalId) {
|
|
clearInterval(intervalId);
|
|
}
|
|
|
|
const checkSetupStatus = async () => { ... };
|
|
checkSetupStatus();
|
|
const newInterval = setInterval(checkSetupStatus, 3000);
|
|
setIntervalId(newInterval);
|
|
|
|
return () => clearInterval(newInterval);
|
|
}, [wasInSetupMode, location.pathname, navigate]);
|
|
```
|
|
|
|
## Definition of Done
|
|
|
|
- [ ] No screen flashing/looping after server restart
|
|
- [ ] Single polling interval active at any time
|
|
- [ ] Clean redirect to login page after setup completion
|
|
- [ ] No memory leaks from uncleared intervals
|
|
- [ ] Setup completion checker continues to work normally
|
|
|
|
## Test Plan
|
|
|
|
1. **Fresh Setup Test:**
|
|
```bash
|
|
# Clean start
|
|
docker-compose down -v --remove-orphans
|
|
rm config/.env
|
|
docker-compose build --no-cache
|
|
cp config/.env.bootstrap.example config/.env
|
|
docker-compose up -d
|
|
|
|
# Complete setup wizard through UI
|
|
# Verify dashboard loads normally
|
|
```
|
|
|
|
2. **Server Restart Test:**
|
|
```bash
|
|
# Restart server manually
|
|
docker-compose restart server
|
|
|
|
# Watch browser for:
|
|
# - No multiple "checking setup status" logs
|
|
# - No 401 errors spamming console
|
|
# - No rapid API calls to /health endpoint
|
|
# - Clean behavior (either stays on page or redirects properly)
|
|
```
|
|
|
|
3. **Console Monitoring Test:**
|
|
- Open browser developer tools before server restart
|
|
- Watch console for multiple interval creation logs
|
|
- Monitor Network tab for duplicate /health requests
|
|
- Verify only one active polling interval after restart
|
|
|
|
4. **Memory Leak Test:**
|
|
- Open browser task manager (Shift+Esc)
|
|
- Monitor memory usage during multiple server restarts
|
|
- Verify memory doesn't grow continuously (indicating uncleared intervals)
|
|
|
|
## Files to Modify
|
|
|
|
- `aggregator-web/src/components/SetupCompletionChecker.tsx` (main component)
|
|
- Potentially related: `aggregator-web/src/lib/store.ts` (auth store)
|
|
- Potentially related: `aggregator-web/src/pages/Setup.tsx` (calls logout before configure)
|
|
|
|
## Impact
|
|
|
|
- **Critical User Experience:** UI becomes unusable after normal server operations
|
|
- **Production Impact:** Server maintenance/restarts break user experience
|
|
- **Perceived Reliability:** System appears broken/unstable
|
|
- **Support Burden:** Users require manual intervention (logout/login) after server restarts
|
|
|
|
## Technical Notes
|
|
|
|
- This bug only manifests during server restart after setup completion
|
|
- Previous fix (commit 7b77641) addressed 401 loop but didn't solve interval cleanup
|
|
- The issue is specific to React effect dependency management
|
|
- Multiple overlapping intervals cause the rapid flashing behavior
|
|
|
|
## Verification Commands
|
|
|
|
After implementing fix:
|
|
|
|
```bash
|
|
# Monitor browser console during restart
|
|
# Should see only ONE "checking setup status" log every 3 seconds
|
|
|
|
# Test multiple restarts in succession
|
|
docker-compose restart server
|
|
# Wait 10 seconds
|
|
docker-compose restart server
|
|
# Wait 10 seconds
|
|
docker-compose restart server
|
|
|
|
# UI should remain stable throughout
|
|
``` |