Workflow SDK 5: i job AI lunghi hanno bisogno di un contratto di annullamento

Tech

Un job AI lungo diventa pericoloso quando non sai cosa continua dopo l’annullamento. Il modello gira ancora, un upload finisce dopo il timeout, o un retry consuma budget dopo il limite quota.

Il 16 giugno 2026 Vercel ha annunciato che Workflow SDK 5 beta supporta AbortController e AbortSignal oltre i confini di workflow e step. Se i runtime durano più a lungo, devono anche fermarsi meglio.

Diagramma di Workflow SDK con segnali AbortController passati agli step e attivati da timeout, annullamento utente o limite quota
Il punto non è il pulsante annulla, ma un contratto operativo esplicito tra workflow, step e cleanup.

Cosa cambia

Un workflow crea un AbortController, passa il signal agli step e chiama abort() su timeout, race, hook o quota. La documentazione dice che il signal resta durable tra suspension, replay deterministico e invocazioni separate.

La cancellazione è cooperativa: lo step deve usare il signal con fetch, signal.throwIfAborted(), signal.aborted o listener.

Perché conta

OCR, report, automazione browser, agent multi-modello e test E2E richiedono runtime lunghi. Senza contratto di annullamento aumentano sprechi, side effect e stati ambigui.

Le discussioni su production-ready e cleanup mostrano una domanda operativa reale.

Impatto

Timeout come policy di prodotto, lavori paralleli che cancellano i perdenti e abort error senza retry rendono il sistema più leggibile.

Checklist

Nomina user, timeout, admin, quota, parent request.

Propaga signal in ogni step costoso.

Distingui run.cancel() da AbortSignal.

Registra cancelled_by_user, timed_out, quota_exceeded.

Testa cleanup di upload, job, email e webhook.

Rischi

SDK 5 è beta/pre-release: inizia piccolo e con rollback.

AbortSignal non annulla side effect remoti né codice che ignora il segnale.

Cosa fare

Disegna i confini di annullamento prima dell’adozione: costo, mutazioni esterne, operazioni non ripetibili.

Controllo in 30 minuti

Le cause di annullamento sono nominate

Ogni step costoso riceve o controlla un signal

Abort e retry sono coerenti

Gli effetti esterni hanno idempotency key

Monitoring distingue cancelled da failed

const controller = new AbortController();
const result = await Promise.race([
  expensiveStep(controller.signal),
  sleep("30s").then(() => null),
]);
if (result === null) controller.abort();

Fonti e approfondimenti