סימולטור כשלים מתגלגלים · AfifAI
מקרה בוחן · תשתיות קריטיות · ⁦2024–2025⁩

סימולציה של כשל אחד שמתגלגל ברשתות החשמל והגז, והמים בשלב הבא

מתכנני חירום בחברה ישראלית לחוסן תשתיות קריטיות יכולים היום לטעון קטלוג נכסים ארצי, להפעיל עליו תרחיש כשל ולראות איך ההשפעה מתפשטת ברשת בצעדים של 15 דקות. הם רואים אילו תחנות משנה, צנרת ולקוחות מאבדים אספקה, לכמה זמן, ולמה.

⁦.NET 8⁩⁦C#⁩SQL Server spatialEF CoreTalend ETLReact + TypeScriptMapbox GLECharts
לקוח
חברה ישראלית לחוסן תשתיות קריטיות (חסוי)
התפקיד שלי
ראש צוות, ארכיטקט ומפתח בפועל
ציר זמן
נובמבר 2024 – אוגוסט 2025 · קטלוג, מפה, ואז סימולציה
סטטוס
נמסר
במבט אחד
⁦900×⁩מהר יותר מזמן אמת: צעד של 15 דקות רץ בשנייה, ותרחיש של 24 שעות מסתיים בכ־⁠1.6 דקות
1 קליקלרענון נתונים מלא: 40 ג׳ובים של ETL, 20 פרוצדורות סנכרון, גאומטריה וקשרים
2פניות לבסיס הנתונים בכל ייבוא קובץ KMZ, במקום כ־⁠2 לכל נכס
⁦20×⁩פחות קריאות סטטוס במסך הריצה החי (משיכה כל 20 שניות ושעון מקומי)
32שגרות ולידציה ב־⁠ETL. שורות פגומות נשמרות ומסומנות.
3 · 18מגזרים וסוגי נכסים בקטלוג אחד
149נקודות קצה REST ב־⁠9 קונטרולרים
432אילוצי תפעול על 159 נכסים ו־⁠169 קשרים בסט הנתונים הארצי
הבעיה

הנתונים היו קיימים, אבל שום דבר לא חיבר ביניהם

הלקוח ממדל איך אירוע חירום לאומי, למשל רעידת אדמה או פגיעה במתקן, מתפשט בתשתיות הקריטיות. חומרי הגלם היו גיליונות אקסל, אחד לכל סוג נכס ומגזר, וכל אחד עם עמודות משלו. הקואורדינטות הגיעו בשלושה פורמטים, הגאומטריה של המפה הגיעה בקובצי KMZ, ולא היה מודל של איזה נכס מזין את מי.

כדי לענות על שאלה כמו ”אם השנאי הזה מאבד ⁦40%⁩ מהקיבולת ב־⁠08:15, אילו לקוחות נשארים בלי חשמל ומתי הם חוזרים?” היה צריך לחשב ידנית מתוך קבצים מנותקים.

מה הובלתי

מקטלוג נכסים לסימולציה שרצה

  • תכננתי את צד השרת: Solution של ‎⁦.NET 8⁩ עם 18 פרויקטים ושלושה בסיסי נתונים, ל־⁠staging של ה־⁠ETL, לקטלוג הראשי ולתוצאות הסימולציה.
  • בניתי את ה־⁠API של הקטלוג: יצירה, קריאה, עדכון ומחיקה, וגם ייבוא וייצוא לאקסל, לכל סוגי הנכסים בחשמל ובגז טבעי.
  • הפכתי את ה־⁠ETL לפעולת API אחת: הרצת ג׳ובי Talend, סנכרון לבסיס הנתונים הראשי, חישוב גאומטריה ואז טעינת הקשרים בין הנכסים.
  • בניתי את השכבה המרחבית: גאומטריה ב־⁠SQL, GeoJSON שנשמר לכל נכס, ייבוא KMZ ושאילתות מפה שמוגבלות לאזור הנראה.
  • תכננתי וכתבתי את מנוע הסימולציה, מגרסה 1 במרץ 2025 ועד גרסה 2 באפריל, ואת מסכי הסימולציה שמעליו.
  • הובלתי את מפתחי הפרונטאנד וה־⁠ETL, עברתי על PRs, וניהלתי ארבע סביבות (dev, QA, stage, production).
ארכיטקטורה

ולידציה ב־⁠staging, סנכרון בטרנזקציה אחת, סימולציה בזיכרון

התרשים רחב מהמסך: החליקו הצידה לצפייה בכולו →

פלט ה־⁠ETL נוחת קודם בבסיס נתונים נפרד של staging. שום נתון לא מגיע לקטלוג שהסימולציה קוראת לפני שעבר ולידציה וסנכרון טרנזקציוני. הסימולציה טוענת את גרף הנכסים לזיכרון פעם אחת, וכותבת תוצאות באצווה אחת לכל צעד.

איך נראית קריסה מדורגת

אירוע אחד, ארבעה צעדים

זו רשת קטנה סינתטית שפועלת לפי הכללים של המנוע. אף שם, ערך או טופולוגיה לא לקוחים מהלקוח. בחרו צעד כדי לראות מה המנוע משנה ואילו אירועי המשך הוא מתזמן.

תקיןמופחת / על סוללהללא אספקה

אירועים שהמנוע תזמן
    החלטות תכנון

    פיזיקה שאפשר להחליף, ומסלול נתונים משעמם

    בסיס נתונים של staging, ואחריו סנכרון MERGE

    Talend כותב לבסיס נתונים נפרד משלו. פרוצדורה אחת מריצה 20 סנכרוני MERGE, אחד לכל סוג, בתוך טרנזקציה אחת. אם הרענון נכשל, הקטלוג נשאר בדיוק כמו שהיה. המחיר: עותק שני של 57 טבלאות הקטלוג, שצריך לשמור מתואם עם הסכמה הראשית.

    אסטרטגיית חישוב לכל סוג נכס

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

    שני מעברים בכל צעד במקום פותר זרימת הספק

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

    המנוע מתזמן לבד את אירועי ההמשך

    כשל עם זמן תיקון מתזמן את ההתאוששות שלו. הפעלת גנרטור מתזמנת ”עלה לאוויר” לפי זמן ההנעה, וצרכן על סוללה מתזמן את ההתרוקנות שלה. המתכננים כותבים רק את האירוע הראשון. המנוע בונה את ציר הזמן ושומר כל אירוע שהוא מייצר.

    לחשב גאומטריה פעם אחת ולשאול לפי חלון התצוגה

    הגאומטריה של נקודות וקווים, וה־⁠GeoJSON שלהן, מחושבות בזמן הסנכרון או העריכה ונשמרות על הנכס. בקשת מפה היא חיתוך מרחבי עם המלבן הנראה, ואחריו שרשור של ה־⁠GeoJSON השמור. המחיר: כל מסלול עריכה חייב לחשב מחדש את הגאומטריה, ולכן זה יושב במתודה אחת בשירות.

    יומן הנדסי

    בעיות שכדאי לזכור

    נובמבר 2024

    18 סוגי נכסים, 18 גיליונות שונים

    לכל סוג נכס היו עמודות, יחידות וערכי בחירה משלו. ייבוא ו־⁠API נפרדים לכל אחד לא היו מחזיקים.

    בניתי שכבת קטלוג גנרית: קונטרולר ו־⁠storage בסיסיים, כלי אחד לייבוא וייצוא אקסל ופרופיל מיפוי אחד. סוג נכס חדש דרש ישות ומיפוי, בלי צנרת חדשה.

    דצמבר 2024

    הרצת ג׳ובי ETL מכפתור באתר

    ג׳ובי Talend הם סקריפטים עצמאיים. בקשת ווב הייתה צריכה להפעיל אותם, לחכות להם, ולא להשאיר תהליכים יתומים כשמישהו מבטל.

    ה־⁠API מפעיל כל ג׳וב כתהליך בן עם סקריפט הפעלה לפי מערכת ההפעלה, ממתין באופן אסינכרוני, והורג את כל עץ התהליכים בביטול. כשל במגזר אחד נרשם ללוג, ושאר המגזרים ממשיכים לרוץ.

    דצמבר 2024

    קואורדינטות בשלושה פורמטים

    בגיליונות המקור הופיעו מעלות־דקות־שניות, מעלות עם דקות עשרוניות ומעלות עשרוניות, מעורבבים.

    שגרות ה־⁠ETL ממירות את שלושתם למעלות עשרוניות ומאמתות אותם. ממרץ 2025, שורות שנכשלות בולידציה נכתבות לטבלת שורות פגומות עם הסיבה, כך שהג׳וב לא נעצר וגם לא מפיל אותן בשקט.

    ינואר 2025

    המפה הייתה צריכה קווים, לא רק נקודות

    המפה הראשונה קראה קובץ GeoJSON סטטי. קווי מתח וצנרת אמיתיים הם פוליליינים עם הרבה קודקודים, והעיצוב של הקווים מקובץ המפה היה צריך לשרוד את הייבוא.

    המרתי נקודות ופוליליינים לגאומטריה של SQL Server, שמרתי GeoJSON על כל נכס, והגשתי את המפה דרך שאילתת חיתוך עם חלון התצוגה. ייבוא KMZ מתאים נכסים לפי מזהה חיצוני, עם שליפה מרוכזת אחת ועדכון מרוכז אחד.

    פברואר 2025

    שאילתות קריאה ששילמו על מעקב שינויים

    שאילתות קריאה גדולות עם כמה Includes נטענו ל־⁠change tracker של EF, למרות ששום דבר לא נשמר.

    העברתי את מסלולי הקריאה האלה ל־⁠no-tracking עם identity resolution. ישויות קשורות לא משוכפלות, וזה בלי עלות המעקב.

    אפריל 2025

    סדר החישוב שינה את התוצאה

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

    גרסה 2 של המנוע ממיינת את הגרף טופולוגית ומריצה שני מעברים בכל צעד: הפוך לביקוש, קדמי לאספקה. האירועים מקובצים לפי נכס ומטופלים לפני החישוב מחדש.

    יוני 2025

    ריצה שאף פעם לא הגיעה ל־⁠⁦100%⁩

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

    יישרתי את נוסחת ספירת הצעדים בין השירות למנוע. מעכשיו כל צעד שומר גם CPU, זיכרון וזמן שחלף, כך שאפשר להסביר ריצות איטיות.

    יולי 2025

    תרחיש ואילוצים בשני מקומות

    המתכננים החזיקו את אירועי הכשל ואת אילוצי הנכסים בקבצים נפרדים, ולכן היה קל להגדיר ריצה לא עקבית.

    ייבוא של חוברת אחת שמשלבת תרחיש ואילוצים, API של תוצאות לפי צעד, ותצוגות שרשרת (עץ, Sankey וגרף כוחות) שמראות איך כשל עובר ברשת.

    תוצאה

    לפני ואחרי

    תחוםלפניאחרי
    רענון נתוניםגיליון לכל סוג, ג׳וב אחרי ג׳ובפעולה אחת מריצה 40 ג׳ובים, סנכרון טרנזקציוני, גאומטריה וקשרים
    שורות מקור פגומותנדחות בלי תיעודנשמרות בטבלת שורות פגומות עם הסיבה
    מפהקובץ GeoJSON סטטי שעובד מראששאילתה חיה לפי חלון התצוגה על גאומטריה ב־⁠SQL, תמיד מעודכנת מול הקטלוג
    ייבוא KMZבגישה של נכס־נכס: כ־⁠2 פניות לבסיס הנתונים לכל נכס2 פניות לקובץ: שליפה מרוכזת אחת ועדכון מרוכז אחד
    ניתוח ”מה אם”חישוב ידני מתוך קבצים מנותקיםצעדים של 15 דקות, 24 שעות ב־⁠כ־⁠1.6 דקות, תוצאות לכל נכס, שרשראות תלות וייצוא לאקסל
    מסך ריצה חימשיכה כל שנייה הייתה 60 קריאות סטטוס בדקה3 קריאות בדקה (כל 20 שניות, בקשות ישנות מבוטלות) ושעון מקומי של שנייה
    • מגזרי החשמל והגז הטבעי רצים בסימולציה מקצה לקצה על סט נתונים ארצי של 159 נכסים, 169 קשרים ו־⁠432 אילוצים.
    • למגזר המים כבר יש סכמה וג׳ובי ETL. אסטרטגיית החישוב שלו היא השלב הבא.
    • כל ריצה נשמרת עם הצעדים, התוצאות לכל נכס, תוצאות התלות, האירועים שנוצרו ומדדי המשאבים, כך שאפשר לשחזר ולבקר אותה.
    • כ־⁠10 חודשים מנקודת הקצה הראשונה של הקטלוג ועד סימולציות רב־מגזריות שרצות, על פני ארבע סביבות.
    סטאק

    טכנולוגיות

    צד שרת
    ⁦.NET 8⁩, ⁦ASP.NET Core⁩ Web API, EF Core, AutoMapper, JWT, NLog
    נתונים
    SQL Server עם טיפוסים מרחביים (NetTopologySuite), פרוצדורות שמורות, סנכרון MERGE
    ETL
    ג׳ובים ו־⁠joblets של Talend, שגרות ולידציה ב־⁠Java
    סימולציה
    מנוע ⁦C#⁩ בתוך התהליך: תור אירועים, Strategy pattern, מעברים טופולוגיים
    פרונטאנד
    React 18 ו־⁠TypeScript עם Vite, Redux Toolkit, Ant Design, Mapbox GL ו־⁠ECharts, ותמיכה בשלוש שפות דרך i18next
    אספקה
    Docker Compose, סקריפטי publish, ענפי dev, QA, stage ו־⁠production

    שיחת אבחון חינם · 30 דקות · ללא התחייבות

    הביאו תהליך אחד. קבלו תוכנית ומספר לשפר.

    כתבו בכמה שורות: איזה תהליך או מערכת, מה כואב היום (זמן, טעויות, עלויות או פיילוט AI שנתקע) ומי עובד עם זה. אחרי שיחה קצרה מקבלים תוך כ־3 ימים תוכנית כתובה והצעת מחיר סגורה.

    לשיחת אבחון חינםafif.mansour@gmail.com

    נפתח מייל מוכן מראש · מענה תוך יום עסקים

    ה־AI קורא. הקוד סופר.

    כל הפרויקטים