# Runbook: Upload Stuck in "uploading" Status ## Signal **Symptômes observables**: - Upload reste en statut `uploading` > 10 minutes (anormal) - Utilisateur ne peut pas accéder au fichier uploadé - Logs: Pas de transition `uploading` → `processing` → `completed` - Métriques: `veza_file_uploads_total{status="uploading"}` reste élevé **Endpoints concernés**: - `POST /api/v1/upload` - Upload initial - `GET /api/v1/uploads/:id/status` - Vérification statut - `GET /api/v1/tracks/:id` - Accès track après upload ## Hypothèses 1. **Job worker down** - Worker qui traite les uploads ne fonctionne plus 2. **Queue bloquée** - RabbitMQ/Job queue saturée ou bloquée 3. **Storage problème** - Fichier non accessible, permissions, espace disque 4. **Processing échoué silencieusement** - Erreur non loggée, statut non mis à jour 5. **Timeout processing** - Traitement trop long, timeout avant completion ## Vérifications ### 1. Vérifier statut upload spécifique ```bash # Via API curl -H "Authorization: Bearer " \ http://localhost:8080/api/v1/uploads//status # Réponse attendue: # { # "success": true, # "data": { # "status": "uploading", # ← Bloqué ici # "progress": 100, # "created_at": "2025-12-15T10:00:00Z" # } # } ``` ### 2. Vérifier logs application ```bash # Chercher upload spécifique grep "" /var/log/veza-backend-api/*.log # Chercher erreurs processing grep -i "upload.*error\|processing.*failed\|job.*failed" /var/log/veza-backend-api/*.log | tail -50 # Chercher jobs worker grep -i "job worker\|process.*upload" /var/log/veza-backend-api/*.log | tail -50 ``` ### 3. Vérifier job worker ```bash # Vérifier processus worker ps aux | grep "job.*worker\|worker.*upload" # Vérifier logs worker (si séparé) tail -100 /var/log/veza-worker/*.log ``` ### 4. Vérifier queue (RabbitMQ) ```bash # Si RabbitMQ activé rabbitmqctl list_queues name messages messages_ready messages_unacknowledged # Vérifier connexion RabbitMQ curl http://localhost:15672/api/queues # (si management activé) ``` ### 5. Vérifier storage ```bash # Vérifier fichier uploadé existe ls -lh /var/veza/uploads// # Vérifier permissions ls -la /var/veza/uploads// # Vérifier espace disque df -h /var/veza/uploads # Vérifier inodes (si problème) df -i /var/veza/uploads ``` ### 6. Vérifier base de données ```sql -- Vérifier statut upload en DB SELECT id, status, progress, created_at, updated_at, error_message FROM uploads WHERE id = ''; -- Chercher uploads bloqués (> 10 min en uploading) SELECT id, status, created_at, updated_at FROM uploads WHERE status = 'uploading' AND created_at < NOW() - INTERVAL '10 minutes' ORDER BY created_at; -- Vérifier jobs en attente SELECT id, type, status, created_at, started_at, completed_at FROM job_queue WHERE type = 'process_upload' AND status IN ('pending', 'processing') ORDER BY created_at; ``` ## Actions Correctives ### Si job worker down 1. **Redémarrer job worker**: ```bash sudo systemctl restart veza-backend-api # ou docker restart veza-backend-api ``` 2. **Vérifier worker démarre**: ```bash grep "Job Worker démarré" /var/log/veza-backend-api/*.log ``` 3. **Relancer processing manuel** (si possible): - Via API admin (si disponible) - Ou directement en DB (voir ci-dessous) ### Si queue bloquée 1. **Vérifier RabbitMQ**: ```bash sudo systemctl status rabbitmq-server # ou docker ps | grep rabbitmq ``` 2. **Redémarrer RabbitMQ** (si nécessaire): ```bash sudo systemctl restart rabbitmq-server ``` 3. **Purger queue** (si nécessaire, ⚠️ perte jobs): ```bash rabbitmqctl purge_queue ``` ### Si fichier manquant/inaccessible 1. **Vérifier fichier existe**: ```bash find /var/veza/uploads -name "**" ``` 2. **Vérifier permissions**: ```bash chown -R veza:veza /var/veza/uploads// chmod -R 644 /var/veza/uploads// ``` 3. **Si fichier manquant**: - Marquer upload comme `failed` en DB - Notifier utilisateur - Documenter perte fichier ### Si processing échoué silencieusement 1. **Forcer re-processing** (via DB): ```sql -- Marquer comme pending pour re-traitement UPDATE uploads SET status = 'pending', updated_at = NOW() WHERE id = '' AND status = 'uploading'; -- Ou créer job manuel INSERT INTO job_queue (id, type, payload, status, created_at) VALUES ( gen_random_uuid(), 'process_upload', jsonb_build_object('upload_id', ''), 'pending', NOW() ); ``` 2. **Vérifier logs après re-processing**: ```bash tail -f /var/log/veza-backend-api/*.log | grep "" ``` ### Si timeout processing 1. **Augmenter timeout** (si configurable): - Modifier timeout dans `internal/jobs/upload_processor.go` - Redémarrer worker 2. **Diviser traitement** (long terme): - Implémenter processing par chunks - Ajouter checkpoints ## Actions Préventives ### Monitoring à ajouter 1. **Alerte uploads bloqués**: ```yaml - alert: VezaUploadsStuck expr: | count(uploads{status="uploading", created_at < now() - 10m}) > 0 ``` 2. **Métrique temps processing**: - Ajouter métrique `veza_upload_processing_duration_seconds` - Alerter si > seuil (ex: 5 minutes) ### Améliorations code 1. **Timeout explicite**: - Ajouter timeout sur processing (ex: 10 min) - Marquer comme `failed` si timeout 2. **Retry logic**: - Implémenter retry automatique (max 3 tentatives) - Backoff exponentiel 3. **Health check job worker**: - Endpoint `/health/worker` vérifiant queue/jobs - Intégrer dans `/readyz` ## Post-Mortem Notes ### À documenter après résolution - **Upload ID affecté**: `` - **Cause racine**: Job worker down / Queue bloquée / Storage / Processing / Timeout - **Durée de l'incident**: De [heure début] à [heure fin] - **Impact**: Nombre d'uploads bloqués, utilisateurs affectés - **Actions prises**: Liste des actions correctives - **Actions préventives**: - [ ] Ajouter monitoring uploads bloqués - [ ] Implémenter timeout explicite - [ ] Ajouter retry logic - [ ] Améliorer logging processing ### Métriques à surveiller post-incident - `veza_file_uploads_total{status="uploading"}` - Doit diminuer - `veza_file_uploads_total{status="completed"}` - Doit augmenter - Temps moyen processing - Doit rester < 5 minutes ## Références - Handler upload: `internal/handlers/upload.go` - Job processor: `internal/jobs/upload_processor.go` (si existe) - Documentation upload async: `docs/UPLOAD_ASYNC.md`