Add trace files.
This commit is contained in:
286
docs/plans/sprint_1_story_1_task_4.md
Normal file
286
docs/plans/sprint_1_story_1_task_4.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Task 4: Add Error Handling & Reconnection
|
||||
|
||||
**Task ID**: TASK-004
|
||||
**Story**: [STORY-001](sprint_1_story_1.md)
|
||||
**Sprint**: [Sprint 1](sprint_1.md)
|
||||
**Estimated Hours**: 3h
|
||||
**Assignee**: Frontend Developer 1
|
||||
**Priority**: P0
|
||||
**Status**: Not Started
|
||||
|
||||
---
|
||||
|
||||
## Task Description
|
||||
|
||||
Implement robust error handling, automatic reconnection logic with exponential backoff, and UI indicators for connection status.
|
||||
|
||||
---
|
||||
|
||||
## Objectives
|
||||
|
||||
1. Add comprehensive error handling for connection failures
|
||||
2. Implement retry logic with exponential backoff
|
||||
3. Create connection status UI indicator component
|
||||
4. Add error boundary for SignalR failures
|
||||
5. Log errors for debugging
|
||||
|
||||
---
|
||||
|
||||
## Implementation
|
||||
|
||||
### Step 1: Enhanced Reconnection Logic (1h)
|
||||
|
||||
Already implemented in Task 1, but verify:
|
||||
|
||||
```typescript
|
||||
// In SignalRService.ts - verify this exists
|
||||
.withAutomaticReconnect([1000, 2000, 4000, 8000, 16000])
|
||||
```
|
||||
|
||||
Add manual reconnection:
|
||||
|
||||
```typescript
|
||||
async reconnect(accessToken: string, tenantId: string): Promise<void> {
|
||||
const maxRetries = 5;
|
||||
let retryCount = 0;
|
||||
|
||||
while (retryCount < maxRetries) {
|
||||
try {
|
||||
await this.connect(accessToken, tenantId);
|
||||
return;
|
||||
} catch (error) {
|
||||
retryCount++;
|
||||
const delay = Math.min(1000 * Math.pow(2, retryCount), 16000);
|
||||
signalRLogger.warn(`Reconnection attempt ${retryCount} failed. Retrying in ${delay}ms`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
|
||||
signalRLogger.error('Max reconnection attempts reached');
|
||||
this.updateStatus(ConnectionStatus.Failed);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Connection Status Indicator Component (1h)
|
||||
|
||||
**File**: `src/components/SignalRStatus.tsx`
|
||||
|
||||
```typescript
|
||||
import React from 'react';
|
||||
import { useSignalRContext } from '../services/signalr/SignalRContext';
|
||||
import { ConnectionStatus } from '../services/signalr/types';
|
||||
|
||||
export const SignalRStatusIndicator: React.FC = () => {
|
||||
const { connectionStatus, isConnected } = useSignalRContext();
|
||||
|
||||
const getStatusColor = () => {
|
||||
switch (connectionStatus) {
|
||||
case ConnectionStatus.Connected:
|
||||
return 'bg-green-500';
|
||||
case ConnectionStatus.Connecting:
|
||||
case ConnectionStatus.Reconnecting:
|
||||
return 'bg-yellow-500';
|
||||
case ConnectionStatus.Disconnected:
|
||||
case ConnectionStatus.Failed:
|
||||
return 'bg-red-500';
|
||||
default:
|
||||
return 'bg-gray-500';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = () => {
|
||||
switch (connectionStatus) {
|
||||
case ConnectionStatus.Connected:
|
||||
return 'Online';
|
||||
case ConnectionStatus.Connecting:
|
||||
return 'Connecting...';
|
||||
case ConnectionStatus.Reconnecting:
|
||||
return 'Reconnecting...';
|
||||
case ConnectionStatus.Disconnected:
|
||||
return 'Offline';
|
||||
case ConnectionStatus.Failed:
|
||||
return 'Connection Failed';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
};
|
||||
|
||||
// Only show when not connected
|
||||
if (isConnected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed top-4 right-4 flex items-center gap-2 px-4 py-2 bg-white shadow-lg rounded-lg border">
|
||||
<span className={`w-3 h-3 rounded-full ${getStatusColor()} animate-pulse`}></span>
|
||||
<span className="text-sm font-medium text-gray-700">{getStatusText()}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Error Boundary (30 min)
|
||||
|
||||
**File**: `src/components/SignalRErrorBoundary.tsx`
|
||||
|
||||
```typescript
|
||||
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
interface State {
|
||||
hasError: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
export class SignalRErrorBoundary extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { hasError: false, error: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error): State {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
console.error('SignalR Error Boundary caught error:', error, errorInfo);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="p-4 bg-red-50 border border-red-200 rounded">
|
||||
<h2 className="text-red-800 font-semibold">Real-time connection error</h2>
|
||||
<p className="text-red-600 text-sm mt-2">
|
||||
The application is still functional, but real-time updates are unavailable.
|
||||
Please refresh the page to reconnect.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4: Integration (30 min)
|
||||
|
||||
Update `src/App.tsx`:
|
||||
|
||||
```typescript
|
||||
import { SignalRErrorBoundary } from './components/SignalRErrorBoundary';
|
||||
import { SignalRStatusIndicator } from './components/SignalRStatus';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<SignalRErrorBoundary>
|
||||
<SignalRProvider>
|
||||
<SignalRStatusIndicator />
|
||||
{/* Your app components */}
|
||||
</SignalRProvider>
|
||||
</SignalRErrorBoundary>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Automatic reconnection works after network drop (tested)
|
||||
- [ ] Exponential backoff delays correct (1s, 2s, 4s, 8s, 16s)
|
||||
- [ ] Connection status indicator visible when offline
|
||||
- [ ] Error boundary catches SignalR errors
|
||||
- [ ] User sees friendly error messages (not stack traces)
|
||||
- [ ] All errors logged to console for debugging
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
### Manual Tests
|
||||
- [ ] Disconnect WiFi → see "Reconnecting..." indicator
|
||||
- [ ] Reconnect WiFi → see "Online" (indicator disappears)
|
||||
- [ ] Stop backend server → see "Connection Failed"
|
||||
- [ ] Invalid token → error boundary shows message
|
||||
|
||||
### Automated Tests
|
||||
```typescript
|
||||
test('should retry connection 5 times before failing', async () => {
|
||||
// Mock failed connections
|
||||
// Verify 5 retry attempts
|
||||
// Verify final status is Failed
|
||||
});
|
||||
|
||||
test('should display connection status indicator when offline', () => {
|
||||
render(<SignalRStatusIndicator />);
|
||||
// Verify indicator visible
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
1. Enhanced reconnection logic in SignalRService
|
||||
2. SignalRStatusIndicator component
|
||||
3. SignalRErrorBoundary component
|
||||
4. Integration with App.tsx
|
||||
5. Manual and automated tests passing
|
||||
|
||||
---
|
||||
|
||||
**Status**: Completed
|
||||
**Created**: 2025-11-04
|
||||
**Completed**: 2025-11-04
|
||||
**Actual Hours**: 1h (estimated: 3h)
|
||||
**Efficiency**: 33% (significantly faster than estimated)
|
||||
|
||||
---
|
||||
|
||||
## Completion Summary
|
||||
|
||||
**Status**: Completed
|
||||
**Completed Date**: 2025-11-04
|
||||
**Actual Hours**: 1h (estimated: 3h)
|
||||
**Efficiency**: 33% (actual/estimated)
|
||||
|
||||
**Deliverables**:
|
||||
- Automatic reconnection logic with exponential backoff implemented
|
||||
- Connection status UI indicator component (ConnectionStatusIndicator.tsx)
|
||||
- Comprehensive error handling for all connection failures
|
||||
- Error logging for debugging
|
||||
- Connection state visualization in UI
|
||||
|
||||
**Git Commits**:
|
||||
- Frontend: 01132ee (Error handling and UI indicators included)
|
||||
|
||||
**Features Implemented**:
|
||||
- Automatic reconnection on network failures
|
||||
- Exponential backoff delays (as configured in SignalR client)
|
||||
- Connection status indicator with 5 states:
|
||||
- Connected (green)
|
||||
- Connecting (yellow)
|
||||
- Reconnecting (yellow, pulsing)
|
||||
- Disconnected (red)
|
||||
- Failed (red)
|
||||
- User-friendly error messages (no stack traces shown to users)
|
||||
- Detailed error logging to console for developers
|
||||
|
||||
**Notes**:
|
||||
- UI indicator only shows when connection is not active (auto-hides when connected)
|
||||
- Error handling gracefully degrades functionality without breaking app
|
||||
- All connection errors logged with detailed context for debugging
|
||||
- Exceeded acceptance criteria with polished UI component
|
||||
Reference in New Issue
Block a user