Skip to content

Critical Performance Issue: Avatar Image Fetching Lacks Size Limits and Timeouts #95

@Puneet04-tech

Description

@Puneet04-tech

Problem Description

The avatar image fetching in src/services/github.service.js has no safeguards against large images or slow responses, leading to potential performance degradation and massive SVG file sizes:

  • No timeout - Avatar fetch can hang indefinitely
  • No size limit - Can fetch arbitrarily large images
  • No image optimization - Converts entire image to base64 without compression
  • No dimension validation - No check for image resolution
  • Cached with profile - Large images stored in cache, consuming memory

Root Cause

The fetchAvatarDataUri function (lines 112-136) lacks:

  1. Request timeout mechanism
  2. Maximum file size validation
  3. Image dimension limits
  4. Image compression/optimization
  5. Fallback to default avatar on failure

Impact

Performance Degradation:

  • Large avatar images (several MB) converted to base64
  • SVG files can become 5-10MB instead of ~50KB
  • Slow SVG rendering in browsers
  • Increased bandwidth usage
  • Poor user experience on slow connections

Cache Bloat:

  • Large avatar data URIs stored in cache
  • Consumes significant memory per cached entry
  • Reduces effective cache capacity
  • With 1000 cache entries and 5MB avatars = 5GB memory usage

Request Hanging:

  • No timeout on avatar fetch
  • If GitHub CDN is slow, request hangs
  • Blocks entire profile generation
  • Cascading performance issues

Current Code Evidence:

// src/services/github.service.js (lines 112-136)
async function fetchAvatarDataUri(avatarUrl) {
  if (!avatarUrl) {
    return null;
  }

  try {
    const response = await fetch(avatarUrl, {  // NO TIMEOUT
      headers: {
        'User-Agent': 'samdev-pulse',
        'Accept': 'image/*',
      },
    });

    if (!response.ok) {
      throw new Error(`Avatar fetch error: ${response.status}`);
    }

    const contentType = response.headers.get('content-type') || 'image/png';
    const buffer = Buffer.from(await response.arrayBuffer());  // NO SIZE LIMIT
    const base64 = buffer.toString('base64');  // NO COMPRESSION
    return `data:${contentType};base64,${base64}`;
  } catch {
    return null;
  }
}

Proposed Solution

  1. Add timeout to avatar fetch (5 seconds)
  2. Add size limit (max 500KB)
  3. Add dimension validation (max 512x512px)
  4. Add image compression using sharp library
  5. Add fallback to default avatar on oversized images
  6. Add cache key separation for avatar data

Files to Modify

  • src/services/github.service.js - Add timeout, size limit, compression
  • package.json - Add sharp dependency for image processing
  • .env.example - Add AVATAR_MAX_SIZE configuration

Acceptance Criteria

✅ Avatar fetch has 5-second timeout
✅ Avatar images limited to 500KB max
✅ Avatar images resized to max 512x512px
✅ Images compressed before base64 conversion
✅ Fallback to default avatar on oversized images
✅ SVG file sizes reduced by 90%+ for large avatars
✅ Cache memory usage reduced significantly
✅ Unit tests for size/dimension validation

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions