Workflow SDK 5: งาน AI ที่รันนานต้องมีสัญญาการยกเลิก

Tech

งาน AI ที่รันนานไม่ได้ยากเพราะเวลานานอย่างเดียว แต่ยากเมื่อไม่มีใครอธิบายได้ว่าอะไรยังทำงานหลังการยกเลิก โมเดลยังถูกเรียก upload ยังจบหลัง timeout หรือ retry ยังใช้ต้นทุนหลัง quota เต็ม

วันที่ 16 มิถุนายน 2026 Vercel ประกาศว่า Workflow SDK 5 beta รองรับ AbortController และ AbortSignal ข้าม workflow และ step เมื่อ agent รันได้นานขึ้น ก็ต้องหยุดได้แม่นขึ้น

ไดอะแกรม Workflow SDK ที่ส่งสัญญาณ AbortController ไปยังขั้นตอนต่าง ๆ และยกเลิกจาก timeout ผู้ใช้ หรือ quota
สิ่งสำคัญคือสัญญาการทำงาน: step ใดรับสัญญาณใด หยุดอย่างไร และ cleanup ใดตรวจสอบได้

มีอะไรเปลี่ยน

workflow สร้าง AbortController ส่ง signal ไปยัง step และเรียก abort() เมื่อ timeout, race, hook หรือ quota monitor ตัดสินใจ เอกสารระบุว่า signal คงทนข้าม suspension, replay และ invocation แยกกัน

การยกเลิกเป็น cooperative: step ต้องส่ง signal ให้ fetch/API ตรวจ throwIfAborted หรือตรวจ aborted

ทำไมสำคัญ

OCR รายงาน browser automation multi-model agent และ test pipeline ต้องการ runtime ยาว หากไม่มีสัญญายกเลิกจะเสีย token, API call และเกิดสถานะคลุมเครือ

คำถามชุมชนเรื่อง production และ cleanup สะท้อนปัญหา operation

ผลต่อ operation

timeout กลายเป็น policy ของ product, parallel work ยกเลิกตัวแพ้ได้, abort error ไม่ retry ทำให้ log ชัดขึ้น

Checklist

แยก user, timeout, admin, quota, parent request

ส่ง signal ให้ทุก step ที่มีต้นทุน

แยก run.cancel() กับ AbortSignal

บันทึก cancelled_by_user, timed_out, quota_exceeded

ทดสอบ cleanup ภายนอก

ความเสี่ยง

SDK 5 ยัง beta/pre-release ควรเริ่มเล็กและมี rollback

Signal ไม่ย้อน side effect และไม่หยุด code ที่ไม่ฟัง signal

ทำตอนนี้

วาด boundary การยกเลิกก่อนทำปุ่ม cancel: ต้นทุน การแก้ state ภายนอก และงานที่ retry ไม่ได้

เช็ก 30 นาที

ตั้งชื่อเหตุผลยกเลิกชัดเจน

step ที่แพงรับหรือตรวจ signal

abort และ retry ไม่ชนกัน

side effect ภายนอกมี idempotency key

observability แยก cancelled กับ failed

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

แหล่งข้อมูล

다른 글