מה זה?

סקריפט ה-ETL מהשיעור הקודם עובד — אבל מישהו צריך להריץ אותו כל יום ידנית? זה לא ריאלי. Scheduling פותר את זה: מריצים את הסקריפט אוטומטית בזמנים קבועים (cron/APScheduler), בלי התערבות אנושית. אבל הרצה אוטומטית בלי פיקוח יוצרת בעיה חדשה — איך יודעים אם היא הצליחה או נכשלה באמצע הלילה? לוגים מובנים (structured logging, מוכר מיחידת ההוספות ב-C#) פותרים את זה — תיעוד מסודר של מה קרה בכל הרצה.

מילות מפתח שחשוב לזכור

• cron — מתזמן משימות מובנה במערכות Unix/Linux, מבוסס תחביר * * * * * (דקה, שעה, יום-בחודש, חודש, יום-בשבוע)

• crontab -e — הפקודה לעריכת רשימת המשימות המתוזמנות של המשתמש הנוכחי

• APScheduler — ספריית Python לתזמון משימות מתוך קוד פייתון עצמו, לא תלוי ב-cron של מערכת ההפעלה

• Structured Logging — לוגים עם רמות חומרה (info/warning/error) במקום print אחיד לכל דבר — מוכר מיחידת ה-Additions ב-C#

# crontab -e — editing the schedule, syntax: minute hour day-of-month month day-of-week
# run every day at 02:00 at night
0 2 * * * /usr/bin/python3 /path/to/etl_script.py

# run every hour on the hour
0 * * * * /usr/bin/python3 /path/to/etl_script.py
# APScheduler — scheduling from within Python code itself
from apscheduler.schedulers.blocking import BlockingScheduler

def run_etl():
    print("Running ETL...")
    # call the ETL function from the previous lesson

scheduler = BlockingScheduler()
scheduler.add_job(run_etl, "cron", hour=2, minute=0)   # every day at 02:00
scheduler.start()
# Structured Logging — instead of just print
import logging

logging.basicConfig(
    filename="etl.log",
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s"
)

def run_etl():
    logging.info("Starting ETL run")
    try:
        # Extract, Transform, Load
        logging.info(f"Successfully processed {len(df)} rows")
    except Exception as e:
        logging.error(f"ETL failed: {e}")   # error level, not info — can be filtered

הסבר עיקרי

cron מול APScheduler — cron הוא כלי מערכת הפעלה (Unix/Linux) — מריץ פקודה חיצונית בזמן קבוע, בלי קשר לשפת התכנות. APScheduler הוא ספריית פייתון — התזמון “חי” בתוך תהליך פייתון רץ, נוח יותר כשרוצים לוגיקת תזמון דינמית (למשל “רק אם תנאי מסוים מתקיים”) או כשמריצים בתוך אפליקציה גדולה יותר, לא רק סקריפט עצמאי.

Structured Logging הוא בדיוק הרעיון מיחידת ה-Additions ב-C# — במקום print אחיד לכל דבר, רמות חומרה (info/warning/error) מאפשרות לסנן (“הראה לי רק שגיאות מהחודש האחרון”) ולדעת מיד אם הרצה מתוזמנת נכשלה, בלי לגלול בין אלפי שורות print זהות. logging.error בתוך except (לא print) הוא ההבדל בין “משהו נרשם איפשהו” ל"אפשר לחפש ולסנן שגיאות במיוחד".

למה תזמון בלי לוגים מסוכן — הרצה אוטומטית ב-02:00 בלילה שנכשלת בשקט (print שאף אחד לא רואה, כי אף אחד לא ליד המסך) שקולה להרצה שלא קרתה בכלל — רק שגילוי הכישלון מתעכב עד שמישהו שם לב שהדוח היומי חסר. לוג לקובץ (etl.log) הוא ה"תיעוד" שמאפשר לבדוק בבוקר בדיוק מה קרה בלילה, גם בלי לצפות בזמן אמת.

יתרונות

Scheduling מבטל צורך בהרצה ידנית חוזרת; APScheduler נותן שליטה תכנותית גמישה מעבר ל-cron הפשוט; Structured Logging הופך דיבוג הרצות אוטומטיות מ"ניחוש" לתהליך ממוקד עם היסטוריה מתועדת.

חסרונות

cron תלוי-מערכת הפעלה (לא עובד ישירות על Windows בלי כלים נוספים); לוגים בלי ניהול (rotation, מחיקת ישן) עלולים לתפוס שטח דיסק רב עם הזמן; תזמון שגוי (טעות בתחביר cron) עלול לגרום להרצה בזמן לא-מתוכנן או לא בכלל, בלי שגיאה גלויה.

נקודות חשובות

• cron = תזמון ברמת מערכת הפעלה; APScheduler = תזמון בתוך קוד פייתון

• תחביר cron: דקה שעה יום-בחודש חודש יום-בשבוע — 0 2 * * * = כל יום ב-02:00

• Structured Logging עם רמות (info/warning/error) מאפשר סינון וחיפוש, בניגוד ל-print גולמי

• הרצה אוטומטית בלי לוגים = כישלון שקוף שמתגלה מאוחר מדי

טעויות נפוצות

• להשתמש ב-print במקום logging בסקריפט מתוזמן — אין תיעוד קבוע לבדיקה מאוחרת יותר

• לטעות בתחביר cron (סדר השדות) ולגרום להרצה בזמן שגוי לגמרי

• לא לתפוס חריגות (try/except) סביב לוגיקת ה-ETL בסקריפט מתוזמן — כישלון “שקט” בלי תיעוד ברור

סיכום

cron (ברמת מערכת ההפעלה) ו-APScheduler (בתוך קוד פייתון) מאפשרים הרצה אוטומטית וחוזרת של סקריפט ETL, בלי התערבות ידנית. Structured Logging — עם רמות חומרה info/warning/error לקובץ לוג, לא print גולמי — הוא הכרחי להרצות אוטומטיות: בלעדיו, כישלון בשעת לילה נשאר בלתי-מגלה עד שמישהו שם לב שהתוצאה חסרה. יחד, אלה הופכים ETL מ"סקריפט שרצתי פעם" לתהליך production אמין ומתועד.

דוקומנטציה רשמית

APScheduler — Documentation

Python — logging module


תרגילים

תרגיל 1 — cron בסיסי

המשימה: כתבו שורת cron שמריצה סקריפט כל יום ראשון בשעה 08:00, והסבירו כל אחד מחמשת השדות.

בדיקה: התחביר נכון (0 8 * * 0), עם הסבר מדויק לכל שדה.

תרגיל 2 — Structured Logging

המשימה: הוסיפו logging לסקריפט ה-ETL מהשיעור הקודם — info בהתחלה ובסיום מוצלח, error אם נזרקת חריגה.

בדיקה: קובץ הלוג מכיל שורות עם רמות חומרה נכונות; הרצה שנכשלת בכוונה (למשל API לא זמין) מתועדת כ-error, לא נעלמת בשקט.


פרויקט מסכם

המשימה: הוסיפו תזמון ולוגים מלאים לסקריפט ה-ETL מהפרויקט המסכם הקודם.

דרישות:

  1. APScheduler שמריץ את פונקציית ה-ETL כל דקה (לצורך בדיקה מהירה בכיתה, לא כל יום)
  2. Structured Logging מלא: info לכל שלב (Extract התחיל/הסתיים, Transform, Load), error על כל כישלון עם פירוט
  3. סימולציה של כישלון (למשל URL שגוי ב-Extract) ווידוא שהוא מתועד ב-error בלוג, בלי להפיל את כל התהליך המתוזמן (ריצה הבאה עדיין תקרה)

בדיקה: קובץ הלוג מציג היסטוריה ברורה של הרצות מוצלחות וכושלות; הרצה שנכשלה לא “עוצרת” את התזמון העתידי — הריצה הבאה עדיין מתבצעת כרגיל.

מה בפרק הבא

בפרק הבא — פרויקט מסכם: Pipeline מלא — צנרת ETL אמיתית שמשלבת Postgres ו-MongoDB, Pandas לעיבוד, קובץ דוח יומי, והתראות אנומליה — הפרויקט שמאחד את כל היחידה.