Resumable Agent Workflows — עצירה והמשך של תהליך בדיוק מאותה נקודה

מאת צוות מדיה דיל · 12.08.2026 · Agent Infrastructure · 5 דק׳

לא כל עצירה היא כשל — לפעמים משתמש צריך לאשר משהו, לפעמים המשימה מתוזמנת להמשך מאוחר יותר. איך בונים workflow שיודע להיעצר ולחזור בדיוק מאיפה שעצר.

סוכן שמטפל בתהליך אישור הלוואה מגיע לשלב שבו הוא חייב אישור אנושי לפני שממשיך — הסכום גבוה מדי לביצוע אוטומטי מלא. הצוות שבנה את המערכת פתר את זה בדרך הפשוטה ביותר: הסוכן עוצר, ומחכה. אבל "מחכה" איך בדיוק? אם ה-process שמריץ אותו נשאר פתוח ומחכה, הוא תופס משאב יקר (worker, זיכרון, לפעמים אפילו חיבור פתוח למודל) במשך שעות עד שמישהו לוחץ "אשר" — וזה לא סקיילבילי כשיש מאות תהליכים ממתינים בו-זמנית. אם, לעומת זאת, ה-process פשוט נעצר ומת, איך הוא יודע לחזור בדיוק לאותה נקודה, עם אותו הקשר, כשהאישור סוף סוף מגיע — אולי יום שלם אחר כך? זו בדיוק הבעיה שפותר Resumable Workflow: היכולת לעצור תהליך במודע, לשחרר את כל המשאבים שהוא תפס, ולחדש אותו מאוחר יותר בדיוק מהנקודה שבה הוא נעצר — בלי לאבד מידע ובלי לחזור על עבודה שכבר בוצעה.

ההבדל בין "נעצר בכפייה" ל"נעצר במודע"

יש שני סוגים שונים לגמרי של עצירה, וחשוב להבחין ביניהם כי הטיפול בכל אחד שונה. עצירה בכפייה היא תוצאה של כשל — קריסה, restart, ניתוק רשת — ועליה עונה מנגנון Checkpoints ושחזור אוטומטי. עצירה במודע היא חלק מהתכנון: הסוכן מגיע לנקודה שבה הוא צריך לחכות — לאישור אנושי, לתשובה ממערכת חיצונית אסינכרונית, לתאריך עתידי מתוזמן — ומודיע במפורש "אני עוצר כאן בכוונה". ההבדל קריטי כי עצירה במודע לא צריכה להיחשב כשל: אין צורך ב-Alert דחוף, ואין צורך בניסיון retry. היא צריכה רק להישמר במצב "ממתין" עם כל המידע הדרוש לחידוש, ולהמתין באורך רוח לטריגר החיצוני שיפעיל אותה מחדש.

מודל ה-Suspend/Resume

הבסיס הטכני ל-Resumable Workflow הוא הפרדה בין "מצב לוגי" ל"תהליך רץ". במקום שהתהליך עצמו יישאר חי וממתין, הוא כותב את כל המצב הנדרש להמשך — היכן הוא נמצא בזרימה, אילו נתונים כבר נאספו, מה בדיוק הוא מחכה לו — ל-storage מתמיד, ואז נסגר לגמרי ומשחרר את כל המשאבים. כשהטריגר (אישור אנושי, callback ממערכת חיצונית, שעון מתוזמן) מגיע, worker חדש לחלוטין — לא בהכרח אותו process, לפעמים אפילו לא אותה מכונה — טוען את המצב השמור וממשיך בדיוק מהנקודה הנכונה.

await workflow.suspend({
  reason: "awaiting_human_approval",
  resumeToken: approvalRequestId,
  state: { loanAmount, applicantData, stepsCompleted },
});
// התהליך נסגר לגמרי כאן, בלי לתפוס משאב

// בהמשך, כשמגיע אישור:
const ctx = await workflow.resume(approvalRequestId);
// ctx מכיל בדיוק את המצב שנשמר, וממשיכים מהצעד הבא

המודל הזה שונה מהותית מ-checkpointing רגיל למקרה כשל: כאן העצירה יזומה, ולכן אפשר לצרף לה מטא-דאטה עשיר יותר — מי צריך לאשר, מה ה-SLA לתגובה, ומה קורה אם האישור לא מגיע בזמן סביר (למשל, escalation אוטומטי אחרי 48 שעות).

Human-in-the-Loop כמקרה קלאסי

אישור אנושי הוא הדוגמה הכי נפוצה ל-Resumable Workflow, אבל חשוב לתכנן אותו נכון מההתחלה. השלב שממתין לאישור צריך לדעת בדיוק אילו פעולות כבר בוצעו (בלתי הפיכות) לעומת אילו עוד לא, כדי שמי שמאשר יבין את המצב האמיתי, לא רק את הבקשה. חשוב גם timeout מפורש: מה קורה אם אף אחד לא מאשר תוך פרק זמן סביר? הגישה הנכונה היא הסלמה (escalation) אוטומטית — התראה למאשר חלופי, או ביטול אוטומטי של הבקשה עם הודעה ברורה — ולא המתנה אינסופית ששוכחת שהיא בכלל קיימת. הנושא הזה נוגע ישירות למחזור החיים של הסוכן, שמתואר ביתר פירוט במדריך Agent Lifecycle Management: תהליך ש"תקוע" בהמתנה לנצח הוא לא פחות בעיה מתהליך שקרס.

Resume על סוכן stateful לעומת stateless

הקלות של Resume תלויה ישירות באיך המצב של הסוכן מנוהל מלכתחילה. סוכן Stateful שכל ה-context שלו חי מחוץ לתהליך — במסד נתונים או ב-storage ייעודי — יכול להיעצר ולהתחדש כמעט בלי מאמץ נוסף, כי אין הבדל מהותי בין "ממשיך באותו process" ל"ממשיך ב-process חדש שטוען את אותו state". סוכן שנשען על state בזיכרון בלבד (in-memory context שנצבר תוך כדי ריצה) לעומת זאת, דורש שכבת המרה נוספת: לפני העצירה צריך לסרייל (serialize) את כל מה שנחוץ להמשך, ולוודא שהוא באמת מלא — כי אם משהו נשכח, ה-Resume ייצור התנהגות שונה מהתהליך שהיה ממשיך ברצף בלי הפרעה.

מתי הפשטות של "לא לעצור בכלל" עדיפה

לא כל תהליך זקוק ליכולת Resume מלאה. משימות קצרות שנמשכות שניות עד דקות בודדות, בלי שלבים שדורשים המתנה ממושכת, פשוט לא מרוויחות הרבה מהמורכבות הנוספת של Suspend/Resume — עדיף שם checkpointing פשוט לצורך שחזור מכשל, ולא מנגנון עצירה מלאה. הסף שבו Resumable Workflow מוצדק הוא כשיש שלב בזרימה שבאופן טבעי אורך זמן לא ידוע מראש — אישור אנושי, המתנה למערכת אסינכרונית חיצונית, תאריך עתידי — ורוצים לשחרר משאבים בזמן ההמתנה במקום לתפוס אותם בחינם. כשמזהים את הצורך הזה מוקדם בתכנון, קל הרבה יותר לבנות אותו כחלק מהארכיטקטורה הבסיסית, מאשר להוסיף אותו בדיעבד לתהליך שכבר נבנה בהנחה שהוא רץ ברצף אחד בלי הפסקות.

שאלה מעשית נוספת שמתגלה רק בסקייל: תהליך שממתין לאישור אנושי יכול להישאר מושהה שעות, ולפעמים ימים — לקוח לא זמין, מאשר בחופשה, תהליך אישור פנימי איטי. אחסון המצב המושהה ב-storage זול ומדרגי (טבלת בסיס נתונים ייעודית, ולא Redis שמתומחר לפי זיכרון) הוא בחירה מודעת שנדרשת ברגע שנפח התהליכים הממתינים גדל. חשוב גם להגדיר TTL ומדיניות ניקוי: תהליך שממתין יותר מפרק זמן סביר בלי תגובה הוא לרוב סימן לבעיה תפעולית — בקשת אישור שנשלחה למאשר הלא נכון, או Webhook שאמור היה להגיע ולא הגיע — ולא רק "עוד תהליך שממתין בשקט". Dashboard שמציג את כל התהליכים המושהים ממוינים לפי זמן המתנה, ולא רק רשימה שטוחה, הוא לרוב הכלי הראשון שחסר לצוותים שמגלים את הבעיה הזו מאוחר מדי.

נקודה אחרונה שקל להזניח: resumeToken עצמו — המזהה שמקשר בין בקשת האישור לתהליך המושהה — חייב להיות ייחודי וקשה לניחוש, לא רק ID עוקב פשוט. אם מישהו יכול לנחש resumeToken של תהליך אחר, הוא עלול "לאשר" בקשה שלא שלו, או לגרום לתהליך להתחדש עם נתונים לא נכונים. זה נראה כמו פרט אבטחה משני, אבל כשה-Resume קשור לפעולה כספית או לפעולה בלתי הפיכה, זו בדיוק אותה קטגוריית סיכון כמו הגנה על מפתח API — ומצדיקה את אותה רמת זהירות.

תגיות: Resumable Workflows · Suspend Resume · Human-in-the-loop · Agent Checkpoints · Stateful Agents

← חזרה לבלוג · צור קשר