Files
ColaFlow/docs/plans/sprint_1_story_1_task_4.md
Yaojia Wang 08b317e789
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Add trace files.
2025-11-04 23:28:56 +01:00

7.3 KiB

Task 4: Add Error Handling & Reconnection

Task ID: TASK-004 Story: STORY-001 Sprint: Sprint 1 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:

// In SignalRService.ts - verify this exists
.withAutomaticReconnect([1000, 2000, 4000, 8000, 16000])

Add manual reconnection:

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

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

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:

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

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