Skip to content

perf(downloader): global fetch semaphore to cap concurrent Range requests under multi-stream load #35

@CCoupel

Description

@CCoupel

Contexte

Depuis le refactoring #200f7e7, ChunkSizeMB et ParallelChunks sont les deux seuls paramètres de téléchargement. ParallelChunks contrôle à la fois la concurrence des downloads ET le nombre de fenêtres de read-ahead par fichier ouvert.

Problème potentiel

Le WindowCache est global et partagé entre tous les fichiers ouverts, mais il n'y a aucun sémaphore global sur le nombre de requêtes HTTP Range simultanées. Chaque ReadAheadReader prefetch indépendamment.

Calcul du cas à risque

À l'ouverture d'un fichier, NewReadAheadReader lance ParallelChunks + 1 requêtes simultanées (les ParallelChunks premières fenêtres + la dernière fenêtre pour l'index MKV/MP4).

Avec N fichiers ouverts simultanément (ex: VLC + explorateur + 2e player) :

Requêtes simultanées à l'ouverture = N × (ParallelChunks + 1)
Régime permanent                   = N × ParallelChunks

Exemple : 4 streams × (4+1) = 20 requêtes Range simultanées vers le même serveur
          8 streams × (4+1) = 40 requêtes Range simultanées

Conséquences observables :

  • Saturation de la connexion réseau vers le serveur média
  • Potentiel rate-limiting ou HTTP 500 côté serveur Plex/Jellyfin/Emby
  • Dégradation de tous les streams au lieu d'un seul

Solution proposée

Ajouter un sémaphore global dans le WindowCache (ou le Downloader) qui limite le nombre total de fetches HTTP actifs, quel que soit le nombre de fichiers ouverts :

// Dans Downloader ou WindowCache
fetchSem chan struct{} // capacité = ParallelChunks (global, pas par fichier)
// Dans doFetch, avant la requête HTTP
d.fetchSem <- struct{}{}
defer func() { <-d.fetchSem }()

Ainsi ParallelChunks garde sa sémantique d'origine — concurrence totale maximale — que ce soit 1 ou 10 fichiers ouverts.

Quand implémenter

Seulement si on constate en pratique :

  • Des HTTP 500 / rate-limit sur Plex ou Emby avec plusieurs streams simultanés
  • Une dégradation mesurable de la qualité des streams existants à l'ouverture d'un nouveau fichier
  • Une consommation réseau excessive en pic à l'ouverture

Fichiers concernés

  • internal/downloader/downloader.go — ajout du sémaphore dans Downloader.Init() et doFetch()
  • internal/downloader/window_cache.go — ou délégation au Downloader

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions