מדוע האינטגרציה של AppSync באפליקציית מובייל נשברת תחת עומסים אמיתיים
האינטגרציה של AppSync באפליקציית מובייל כמעט תמיד עוברת חלק בסביבת הבדיקות ומתחילה להתפרק בשטח. הסיבה אינה בשירות עצמו, אלא בכך שלקוח המובייל פועל בתנאים שאין לקוד צד השרת: הרשת נעלמת באמצע בקשה, האפליקציה מועברת לרקע, המכשיר מחליף Wi-Fi לרשת סלולרית.
סנכרון נתונים באפליקציית מובייל אינו בקשה אחת, אלא חילוף מתמיד בין המטמון המקומי, תור השינויים שלא נשלחו והשרת.
הכשל הטיפוסי הראשון — חוסר סנכרון של המטמון המקומי. הלקוח רשם שינוי במצב לא מקוון, שלח אותו מאוחר יותר, ובזמן הזה השרת כבר קיבל עדכון ממכשיר אחר. בלי גרסאות לרשומות ואסטרטגיית פתרון קונפליקטים, התשובה האחרונה דורסת בשקט נתונים עדכניים יותר, והמשתמש רואה מצב מיושן.
מצב לא מקוון באפליקציית מובייל נשען לא על "שמירה לבסיס נתונים", אלא על סדר קפדני של החלת מוטציות וכלל מפורש שקובע איזו גרסה של הרשומה מנצחת.
השני — כפילויות של מנויים בזמן אמת. המסך נוצר מחדש בסיבוב או בחזרה מהרקע, ובכל פעם פותח חיבור חדש, והישנים לא נסגרים. הלקוח מקבל את אותו אירוע פעמיים-שלוש, המונים מוכפלים, והערוץ מחזיק סוקטים מיותרים ושורף סוללה. הפתרון הוא קישור המנוי למחזור החיים של המסך ונקודת מנוי יחידה ברמת ה-store, ולא ברמת ווידג'ט בודד.
השלישי — ירידה בביצועים בעת החלפת רשת. החיבור נקטע, הלקוח עובר לחיבור מחדש עם השהיה הולכת וגדלה, ובלי טיפול נכון בניתוק הולכים לאיבוד אירועים שהגיעו ברגע המעבר. המשתמש רואה רשימה "קפואה", אף שהנתונים בשרת כבר התעדכנו.
כל שלושת הכשלים מתגלים לא מיד, אלא תחת עומס אמיתי וברשת חלשה — לכן בהמשך נבחן כיצד זה נסגר ברמת הארכיטקטורה של הלקוח.
מה נותנת אינטגרציה נכונה של AppSync: מצבי סנכרון והשפעתם
מצבי סנכרון: מה משתנה במספרים
מצב זמן אמת מחזיק ערוץ פתוח אל השירות: שינוי בשרת מגיע אל המכשיר בשברירי שנייה, והכתיבה בחזרה יוצאת מיד. זה מה שנדרש לצ'אטים, מעקב הזמנות ורשימות משותפות — השהיית עדכון הנתונים מפסיקה להיות מורגשת לעין.
המחיר — חיבור קבוע וטיפול קפדני בניתוקים: בלי הרשמה מחדש לאחר אובדן רשת הממשק "קופא" בשקט ומציג נתונים מיושנים.
סנכרון תקופתי סוקר את השרת לפי לוח זמנים ועולה פחות במשאבים, אך יוצר חלון של חוסר סנכרון — בערוצים איטיים הוא גדל. תור שינויים במצב לא מקוון סוגר את התרחיש השלישי: עריכות מצטברות locally ויוצאות במקבץ עם הופעת הרשת, ולכן האפליקציה נשארת עובדת במטרו ובמחסן.
השאלה המרכזית כאן — פתרון קונפליקטים: אסטרטגיית "הכתיבה האחרונה מנצחת" פשוטה, אך מאבדת עריכות של אחרים, בעוד מיזוג מבוסס גרסאות לפי שדות שומר על שני הצדדים.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| זמן אמת | צ'אטים, סטטוסים, עבודה משותפת | דורשת רשת יציבה, חזרה לאחור מורכבת יותר |
| סקירה תקופתית | קטלוגים, דוחות, עדכונים נדירים | חלון חוסר הסנכרון גדל עם המרווח |
| תור לא מקוון + מיזוג | שדות, מחסנים, עובדי שטח | נדרשת אסטרטגיית קונפליקטים מפורשת |
בפועל משלבים מצבים: ספרי עזר נמשכים בסקירה, ישויות קריטיות — בזרימה, והכתיבה תמיד עוברת דרך תור עם גרסאות. פריסה כזו מסירה מחלקה שלמה של כשלים — עריכות שאבדו בעריכה בו-זמנית ומסכים "תקועים" לאחר ניתוק הרשת. אנו מגדירים זאת ב-AWS AppSync, שבו מנויים, אחסון לא מקוון וכללי מיזוג מתוארים באופן הצהרתי.
AWS AppSync
שלבי יישום: מביקורת סכימת הנתונים ועד מסירת התיעוד
יישום הסנכרון מתחיל לא בקוד, אלא בביקורת סכימת הנתונים: אילו טיפוסים ושדות כבר קיימים, כיצד בנויים הקשרים, היכן לקוחות כותבים ישירות למסד הנתונים, והיכן קוראים תצוגות מיושנות.
בשלב זה אנו מתעדים את מפת השאילתות והמינויים, כדי שפעולות חדשות לא ישכפלו פעולות קיימות ולא ימשכו נתונים מיותרים אל המכשיר הנייד.
- ביקורת סכימת הנתונים והזרימות הנוכחיות. משווים מודלים, הרשאות גישה לפי פעולות, ומנתחים אילו מסכים באפליקציה קוראים וכותבים אילו ישויות. התוצר — רשימת התנגשויות ומקומות שבהם הסנכרון ישבור את הלוגיקה הקיימת.
- תכנון הסכימה היעד. מגדירים טיפוסים, מפתחות חלוקה ומיון, אסטרטגיית פתרון התנגשויות בעת עריכה בו-זמנית ממספר מכשירים, וכללי הרשאה לפי בעל הרשומה.
- הגדרת סנכרון ומצב לא מקוון. מחברים אחסון מקומי במכשיר, מגדירים תורים של שינויים מושהים ושליחה חוזרת לאחר שחזור החיבור, כדי שהאפליקציה תעבוד ללא רשת ולא תאבד עריכות.
- בדיקת עומסים של האפליקציה הניידת. מריצים תרחישים עם מספר רב של מינויים בו-זמניים, מעברים תכופים בין רשתות ועריכות המוניות. בוחנים כיצד מתנהגים זמן התגובה, נפח הנתונים המועברים וצריכת הסוללה.
- אופטימיזציה לפי תוצאות המדידות. מסירים שדות מיותרים מהתגובות, מפצלים שאילתות כבדות, ומגבילים את תדירות העדכונים במקומות שבהם הממשק מסתפק בסקירה תקופתית.
- מסירת התיעוד. מוסרים תיאור הסכימה, כללי הגישה, תרחישי הסנכרון וההתנהגות הלא מקוונת, הוראות לפריסת סביבות ורשימת בדיקה לצוות הלקוח.
סדר עבודה זה מפחית את הסיכון שיהיה צורך לבנות את הסנכרון מחדש לאחר התלונות הראשונות של משתמשים על אי-התאמה בנתונים. תארו את המשימה — נחזור עם הערכה ותוכנית לכל שלב.
במה שונה מצב לא־מקוון עם מסד נתונים מקומי מעבודה ישירה מול השרת?
עבודה ישירה מול השרת משמעה שכל מסך באפליקציה ממתין לתשובת הרשת. כל עוד יש חיבור, זה נראה פשוט: הבקשה נשלחה, הנתונים הגיעו, הממשק התעדכן. אבל ברגע שהחיבור נעלם — רכבת תחתית, מרתף, נדידה, אנטנה עמוסה — הבקשות מתחילות להיתקע, המסכים מציגים ריק, והמשתמש או ממתין או עוזב. אינטגרציה של AppSync באפליקציה לנייד בנויה בדיוק סביב כך שהפער הזה לא יהיה גלוי לאדם.
מצב לא־מקוון עם מסד נתונים מקומי הופך את הסכימה: האפליקציה כותבת וקוראת מהאחסון במכשיר, והרשת הופכת לסנכרן ברקע. המשתמש עובד באופן מיידי, ללא תלות באיכות החיבור, והשינויים נשלחים לשרת כשהערוץ חזר. המחיר — שכבת סנכרון שצריך לתכנן: תור פעולות, ניסיונות חוזרים, סדר ההחלה.
פתרון קונפליקטים בנתונים — זה העיקר שבו שתי הגישות נבדלות במורכבות. בבקשות ישירות לשרת אין כמעט קונפליקט: השרת הוא מקור האמת היחיד, הכתיבה האחרונה מנצחת.
במצב לא־מקוון שני מכשירים יכלו לערוך רשומה אחת בזמן שהיו ללא רשת, ובסנכרון צריך להחליט איזו גרסה נכונה: לפי זמן השינוי, לפי גרסת הרשומה או באמצעות מיזוג שדות.
לפי נפח התעבורה ההבדל גם מורגש. המודל הישיר מושך נתונים בכל פתיחה של מסך — בערוץ חלש זה מורגש גם במהירות וגם בצריכה. מסד נתונים מקומי מספק נתונים מהאחסון, וברשת עוברים רק שינויים — סנכרון דלתא במקום שליפה מלאה.
הבחירה אינה בינארית: בדרך כלל לוקחים מסד נתונים מקומי לנתוני משתמש ובקשות ישירות למה שחייב להיות עדכני — סטטוסים, תשלום, הרשאות גישה.
מקרה בוחן: כיצד סילקנו אי-סנכרון נתונים באפליקציה עם אלפי משתמשים פעילים
הלקוח — שירות משלוחים עם מאות שליחים במשמרת ועשרות אלפי משתמשים פעילים. האפליקציה עבדה על בקשות REST: סטטוס ההזמנה נמשך בסקירה כל כמה שניות, ושינויים ממכשירים שונים של אותו חשבון דרסו זה את זה.
בעומסי שיא שיעור הקונפליקטים הגיע ל-18% מכלל שינויי הסטטוס, ולאחר אובדן רשת הלקוח הציג נתונים מיושנים עד להפעלה מחדש ידנית — השחזור ארך דקות ודרש פעולות מהמשתמש.
מה עבדנו מחדש בשכבת הסנכרון
העברנו את חילופי הנתונים לשכבת GraphQL מנוהלת עם מנויים: הלקוח כבר לא סוקר את השרת, אלא מקבל שינויים בערוץ.
כל מוטציה עוברת דרך resolver עם בדיקת גרסת הרשומה — אם המכשיר שולח נתונים המבוססים על מצב מיושן, השרת דוחה את הפעולה ומחזיר את הגרסה המעודכנת, והלקוח מיישם אותה ללא מעורבות המשתמש. זה ביטל את סוג הכשלים "האחרון שכתב מנצח", שבגללו אבדו עריכות.
מדדים לפני ואחרי
| מדד | לפני | אחרי |
|---|---|---|
| שיעור קונפליקטים בשינויים | עד 18% | מתחת ל-1% |
| שחזור לאחר אובדן רשת | דקות, ידנית | שניות, אוטומטית |
| סוג כשל "אובדן עריכות" | קבוע | סולק |
| עומס על השרת מסקירות | קבוע | רק שינויים בפועל |
בנפרד הגדרנו תור אופליין: פעולות שבוצעו ללא רשת נשמרות מקומית ומיושמות עם שחזור החיבור בבדיקת גרסה. זה סגר את התרחיש שבו שליח הזין סטטוס במרתף ואיבד אותו.
AWS AppSync סיפק שכבת מנויים ו-resolvers מנוהלת ללא תשתית זמן אמת משלו — הצוות לא בזבז זמן על תחזוקת שרתי חיבורים.
לאחר העבודה מחדש שיעור הקונפליקטים ירד ביותר מפי עשרים, השחזור לאחר אובדן רשת הפסיק לדרוש פעולות מהמשתמש, והעומס מסקירות קבועות הוחלף בזרימה של שינויים בפועל בלבד. תארו את המשימה שלכם — נחזור עם הערכה ותוכנית עבודה.
ספקות טכניים לפני ההתחלה: תאימות, מיגרציה, rollback, הרשאות גישה
לפני תחילת האינטגרציה של AppSync, לקוחות שואלים לרוב את אותה שאלה: מה יקרה לאפליקציה הקיימת ולנתונים שלה.
אנו עונים באופן ענייני — אינטגרציה של AppSync אינה מחייבת שכתוב מלא של הלקוח: קריאות REST קיימות ומטמון מקומי ממשיכים לפעול במקביל, ושכבת ה-GraphQL מתחברת מעל, בהתאם למוכנות המסכים.
מיגרציית הנתונים מתבצעת לפי הסכמה "כתיבה כפולה → השוואה → החלפת קריאה", ולכן בכל שלב קיימת נקודת חזרה.
מה אם לאחר ההחלפה תתגלה אי-התאמה בנתונים?
חזרה לאחור (rollback) של השינויים מובנית לתוך הסכמה עצמה: הקריאה חוזרת למקור הקודם בשינוי אחד של קונפיגורציה, ללא שחרור גרסה של האפליקציה. הכתיבה הכפולה נשמרת, ולכן אי-ההתאמה נסגרת באמצעות השוואה חוזרת, ולא בשחזור ידני.
הרשאות ותפקידים מתוארים במדיניות נפרדת — לכל סביבה יש סט הרשאות משלה, וסביבת הייצור מבודדת מקווי הבדיקה.
מה אם לצוות אין ניסיון עם AppSync? אנו מעבירים תיעוד של האינטגרציה: סכמת טיפוסים, דוגמאות לשאילתות ולמוטציות, ופירוט ההרשאה לפי תפקידים. המהנדסים של הלקוח מצטרפים לעבודה בשלב הגדרת ה-resolvers, ולא לאחר המסירה.
מה אם יהיה צורך להחליף ספק הרשאה? שכבת הגישה מופרדת מהלוגיקה העסקית — החלפת ספק נוגעת בקונפיגורציה, ולא בקוד המסכים.
בסיום המסירה הלקוח מקבל:
- סכמת נתונים ותיאור טיפוסים עם דוגמאות לשאילתות;
- קונפיגורציות של סביבות עם הפרדת הרשאות גישה ותפקידים;
- נוהל מיגרציית נתונים עם נקודות השוואה ותנאי rollback;
- הוראות לחזרה לאחור של שינויים ללא שחרור גרסה של האפליקציה;
- תיעוד האינטגרציה עבור הצוות של הלקוח;
- סט בדיקות לקבלה — אילו תרחישים וכיצד לבדוק.
תארו את המשימה — נחזור עם הערכה ותוכנית: נבחן את ה-stack הנוכחי, נקבע את סדר המיגרציה ונקבע את נקודות ה-rollback לפני תחילת העבודה.
לוחות זמנים של שלבי ההטמעה: מה קורה ובאיזה סדר
סדר השלבים בנוי כך שכל צעד עוקב נשען על הצעד הקודם שנבדק: תחילה מקבעים את מודל הנתונים ואת כללי הגישה, לאחר מכן מרימים את הסנכרון, ורק אז מעבירים אליו מסכים חיים. תוכנית אינטגרציה כזו מאפשרת לעצור בכל שלב ולקבל אפליקציה עובדת, ולא אוסף של מודולים חצי-מוכנים.
שלבים 3–5 מתנהלים בחפיפה חלקית: בזמן שמהנדס אחד מוביל את הסנכרון, השני מכין את העברת המסכים — כך לוח הזמנים הכולל של ההטמעה מתקצר בכשליש בקירוב ללא אובדן שליטה.
לוחות הזמנים המשוערים מצוינים עבור אפליקציה בעלת מורכבות בינונית; על הניתוח משפיעים מספר המסכים ועומק תרחישי האופליין, ולכן את התוכנית הסופית מקבעים לאחר השבוע הראשון של העבודה, כאשר סכימת הנתונים כבר נראית במלואה.
בנפרד מקצים שלב של עומס וכשל: הוא מראה כיצד האפליקציה מתנהגת בעת ניתוק החיבור ובחזרה לרשת, ולעיתים קרובות חושף קונפליקטים בכתיבה שאינם נראים על נתוני בדיקה. בעקבות שלב זה, תיקונים בסכימה מבוצעים לפני המסירה, ולא לאחר היציאה לפרודקשן.
AWS AppSync







