# Scheduling ולוגים — cron, APScheduler ולוגים מובנים📖 שיעור

## מה זה?

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

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

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

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

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

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

```bash
# 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
```

```python
# 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()
```

```python
# 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](https://apscheduler.readthedocs.io/)

[Python — logging module](https://docs.python.org/3/library/logging.html)

---

## תרגילים

### תרגיל 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 לעיבוד, קובץ דוח יומי, והתראות אנומליה — הפרויקט שמאחד את כל היחידה.
