UpcutToutes les éditions

Édition #1 · 29 juillet 2026

Fiabilité, file d’attente & clips qui restent

Fin juillet, on a reconstruit le cœur du pipeline clips. Moins de jobs fantômes, plus de capacité, une facturation plus juste — et une UI qui ne clignote plus pour rien.

En une phrase

Upcut peut maintenant enchaîner beaucoup plus de générations en parallèle sans perdre tes clips à la fin — ni les marquer en erreur alors qu’ils sont prêts.

  1. 01 — Scale

    Plusieurs machines, une seule file

    Avant, chaque serveur Upcut gardait les jobs clips dans sa propre mémoire. Un redémarrage, un second serveur, et le job pouvait « disparaître » : l’interface affichait une erreur alors que le travail n’était peut‑être pas perdu — juste invisible.

    On a basculé sur une file partagée dans Supabase. Tous les workers Railway piochent le prochain job dans le même ordre (FIFO), un à la fois par machine. Résultat : on peut monter à plusieurs replicas sans se marcher dessus.

    • 1 job complet par replica (download + Whisper + rendu) pour ne pas faire exploser ffmpeg
    • Jusqu’à 3 clips par vidéo en production
    • Estimation de place dans la file côté interface

    La file se vide, même quand beaucoup de créateurs lancent des jobs en même temps.

  2. 02 — Bug critique

    Les clips « terminés » qui apparaissaient en erreur

    Le symptôme le plus pénible : le worker avait bel et bien fini (clips uploadés), mais ton projet affichait STALE_JOB_TIMEOUT — zéro clip visible.

    Un nettoyeur automatique (reaper) croyait que le job était mort parce qu’il attendait trop longtemps dans la file. Dès que le backend passait à « done », le reaper marquait encore l’UI en erreur… sans recopier les clips.

    • Dès qu’un job finit côté worker, on synchronise immédiatement la fiche projet
    • Si le backend est done avec des clips, on promote — on ne STALE jamais
    • Un trigger Postgres garantit le miroir même si un worker crash pile au mauvais moment
    • L’API projet soigne aussi les anciens faux STALE au prochain chargement

    On a restauré une quinzaine de projets zombies en prod. Depuis : 0 nouveau cas STALE de ce type.

  3. 03 — Race technique

    Done à l’écran, « 80 % » côté serveur

    Autre fantôme : l’UI montrait tes clips (done), pendant que le serveur repassait à « processing » bloqué à 80 %.

    Cause : une course. Le dernier update de progression (80 % = tous les clips rendus) partait en parallèle et pouvait écraser le statut « done » écrit une fraction de seconde plus tard — en vidant au passage la liste des clips côté base.

    • Les écritures d’état sont maintenant sérialisées par job
    • Interdiction de downgrader un job terminé vers « en cours »
    • setDone attend bien la persistance avant de lâcher la main
    • Trigger SQL : même attaque simulée en prod → le done tient

    Plus de projets « done » qui repartent magiquement à 80 %.

  4. 04 — File longue

    Ne plus tuer les jobs qui attendent tranquillement

    Avec une vraie file, attendre 40 minutes avant d’être pris en charge peut être normal (beaucoup de monde, jobs longs).

    L’ancien reaper se basait seulement sur la date de création : il tuait des jobs encore pending. On a aussi corrigé un reclaim trop agressif qui volait des jobs Whisper/ffmpeg encore vivants.

    • On ne touche pas aux jobs dont le backend est encore pending ou processing
    • Reclaim uniquement si plus de heartbeat depuis assez longtemps

    Attendre dans la file ≠ erreur. Seuls les vrais zombies (worker mort) sont recyclés.

  5. 05 — Interface

    Moins de flicker pendant le polling

    Quand le backend mettait trop longtemps à répondre, l’UI passait parfois en erreur puis revenait — un flash désagréable sur la page projet.

    Désormais, un timeout de poll est un soft-fail : on garde le dernier statut connu au lieu de faire croire que le job a planté.

    La page projet respire : plus de yo-yo loading → erreur → loading.

  6. 06 — Argent

    Stripe + crédits qui ne double-comptent pas

    Le checkout Creator / Studio passe par Stripe (plus Lemon Squeezy sur le parcours principal).

    La facturation des minutes de clips est retry-safe : même si tu recharges la page pile au moment où le job passe à done, on ne te re-débitera pas.

    Upgrade clair depuis les tarifs, crédits cohérents même en cas de retry réseau.

  7. 07 — Qualité clips

    Whisper, uploads, split & rendu

    Dans le même sprint : découpage Whisper plus robuste, hooks plus propres sur les uploads, moins de faux positifs split sur les monologues, et un réglage ffmpeg pour éviter les plantages mémoire sur Railway Hobby.

    Les uploads peuvent aussi court-circuiter la détection de « moments viraux » quand tu sais déjà ce que tu veux couper — moins d’attente inutile.

    Moins d’échecs silencieux au rendu, meilleurs découpages sur podcasts et longs formats.

Chronologie express

  • 28/07File partagée multi-replicas + capacité ×N
  • 28/07Billing crédits idempotent + Stripe au premier plan
  • 29/07Reaper STALE corrigé — plus de jobs morts à tort
  • 29/07Poll UI soft-fail — plus de flicker
  • 29/07Sync forcée done → projet + heal des zombies
  • 29/07Race 80 % neutralisée (code + trigger SQL)

Pour les curieux

Sous le capot, sans jargon inutile

Tables clés : clip_jobs (ce que tu vois) et clip_backend_jobs (ce que les workers exécutent). Elles doivent rester alignées.

Claim SQL FIFO avec verrouillage coopératif, heartbeats, triggers Postgres pour le miroir done et l’interdiction de downgrade.

Détail technique interne : docs/MODIFS_28-29_JUILLET_2026.md dans le repo.

Prêt à générer ?

Colle un lien YouTube ou Twitch — Gaming, talk ou podcast, les clips suivent ce que tu as lancé.