Idempotency ב-API: איך מונעים חיוב כפול כשהרשת נכשלת
מאת צוות מדיה דיל · 30.08.2026 · טכנולוגיה · 6 דק׳
בקשת רשת יכולה להישלח פעמיים בלי שאף אחד התכוון לזה. Idempotency הוא העיקרון שמבטיח שגם אז, התוצאה הסופית נשארת נכונה.
לקוח שולח בקשת תשלום, החיבור נקטע לפני שהתשובה חוזרת, והלקוח (או הקוד שמריץ ניסיון חוזר אוטומטי) שולח את אותה בקשה שוב. השאלה הקריטית: האם המשתמש חויב פעמיים? Idempotency הוא העיקרון שמבטיח שהתשובה היא לא.
הגדרה מדויקת: מה זו פעולה אידמפוטנטית
פעולה אידמפוטנטית היא פעולה שהרצה שלה פעם אחת או כמה פעמים ברצף מובילה לאותה תוצאה סופית בדיוק. "מחק את הרשומה X" אידמפוטנטית — אחרי הרצה ראשונה הרשומה נמחקת, והרצות נוספות פשוט לא משנות שום דבר נוסף. "הוסף 10 שקלים ליתרה" לא אידמפוטנטית — כל הרצה נוספת מוסיפה עוד 10.
GET, PUT, DELETE: אידמפוטנטיים מטבעם
לפי הסטנדרט, GET (קריאה) ו-DELETE (מחיקה) אמורים להיות אידמפוטנטיים מטבעם, וכך גם PUT (עדכון מלא של רשומה לערך נתון). POST, לעומת זאת, לרוב יוצר רשומה חדשה בכל קריאה — ולכן הוא הבעיה המרכזית שדורשת טיפול מפורש.
Idempotency Key: הפתרון המעשי ל-POST
הלקוח מייצר מזהה ייחודי לכל פעולה (Idempotency Key) ושולח אותו עם הבקשה. השרת שומר את המזהה יחד עם התוצאה, וברגע שמגיעה בקשה עם אותו מזהה שוב, הוא פשוט מחזיר את התוצאה השמורה במקום לבצע את הפעולה מחדש — גם אם הבקשה הכפולה הגיעה בגלל ניסיון חוזר אוטומטי אחרי timeout.
איפה שומרים את המזהים
מזהי Idempotency נשמרים בדרך כלל עם תוקף מוגבל (למשל 24 שעות) במסד נתונים מהיר או ב-Redis, לא לצמיתות. תוקף קצר מדי מסכן חיוב כפול אם ניסיון חוזר מגיע מאוחר; תוקף ארוך מדי צובר עלות אחסון מיותרת. הבחירה תלויה בזמן המקסימלי הסביר לניסיון חוזר במערכת הספציפית.
Race Condition: כשבקשות כפולות מגיעות בו-זמנית
אם שתי בקשות עם אותו מזהה מגיעות ממש באותו רגע, שתיהן עלולות "לא לראות" את השנייה ולהתחיל לעבד במקביל. הפתרון: נעילה קצרה ברמת המזהה עצמו — הבקשה הראשונה נועלת, מבצעת, ומשחררת; הבקשה השנייה מחכה לנעילה ואז מקבלת את התוצאה השמורה, לא מבצעת פעולה נוספת.
מעבר ל-API: אירועים ועיבוד תורים
אותו עיקרון חל גם על עיבוד הודעות מתור — הודעה עלולה להישלח פעמיים בגלל ניסיון חוזר, ועיבוד לא-אידמפוטנטי שלה יוצר תופעת לוואי כפולה. זה בדיוק הנושא שהעלינו במאמר על Event-Driven Architecture — עקרון אחד, כמה הקשרים שונים.
עלות ההזנחה
API שלא מתוכנן לאידמפוטנטיות נראה תקין ברוב הזמן, כי רוב הבקשות לא נכשלות באמצע. הבעיה מופיעה בדיוק כשהיא הכי כואבת — עומס גבוה, תקלת רשת זמנית, בדיוק כשהמערכת הכי פחות יכולה להרשות לעצמה חיוב כפול או פעולה שגויה.
Idempotency בממשק המשתמש עצמו
מעבר לשכבת השרת, גם הלקוח יכול לצמצם סיכון בפועל: השבתת כפתור "שלח" מיד לאחר לחיצה מונעת הרבה מקרי כפילות בפועל, גם אם היא לא תחליף לטיפול נכון בצד השרת. שתי השכבות משלימות זו את זו — צד לקוח מונע רוב המקרים, וצד שרת מבטיח נכונות גם כשמנגנון הצד לקוח נכשל.
תיעוד ה-API כחלק מהחוזה
API שמצפה לקבל Idempotency Key צריך לתעד את זה במפורש כחלק מהחוזה עם צרכני ה-API — אילו נקודות קצה דורשות אותו, מה טווח התוקף, ומה קורה אם מגיעה בקשה זהה אחרי שהמזהה כבר פג. חוזה ברור מונע הפתעות אצל צוותים שמשתמשים ב-API בלי לדעת את הפרטים הפנימיים.
Idempotency ותשלומים — המקרה הקריטי ביותר
בשום מקום Idempotency לא קריטית יותר מאשר בתשלומים: ספקי סליקה כמעט תמיד דורשים Idempotency Key בכל בקשת חיוב, בדיוק כי עלות חיוב כפול, גם באחוז זעיר של המקרים, גדולה בהרבה מהמאמץ הנוסף להטמיע את המנגנון נכון מההתחלה.
רוצים לוודא שה-API שלכם עמיד לניסיונות חוזרים? מוזמנים לפתוח שיחה בוואטסאפ.
תגיות: Idempotency · API Design · Retry Logic · Idempotency Key