מה קורה
שלושה מודולים מדליקים לקוח Sentry כבר כשמייבאים אותם, בלי שאף נקודת כניסה ביקשה:
main.py — קורא ל-init_sentry() ברמה העליונה של המודול (בתוך try), מיד אחרי setup_structlog_logging.
services/webserver.py — אותו דבר, ב-try שבראש הקובץ.
webapp/app.py — sentry_sdk.init(...) ברמת המודול, תחת if _SENTRY_AVAILABLE and config.SENTRY_DSN.
init_sentry (observability.py) לוקח את הכתובת מ-SENTRY_DSN בסביבה, ואם אין — מ-config.SENTRY_DSN. כלומר כל ייבוא של main — טסט, סקריפט שצריך פונקציה אחת, importlib.reload — בונה לקוח שמדבר עם הרשת, עם כל האינטגרציות ש-sentry-sdk מדליק לבד כשהספרייה שלהן מותקנת (auto_enabling_integrations, ברירת המחדל). נמדד בתהליך הבדיקות, על sentry-sdk 2.42.1: אחרי importlib.reload(main) עם SENTRY_DSN בסביבה, הלקוח עלה עם 14 אינטגרציות — ביניהן starlette, pymongo, redis, httpx, aiohttp ו-flask — והן עוטפות את הספריות האלה עד סוף התהליך.
איך זה נשך
זה מה שהפך importlib.reload(main) בבדיקות למתג של Sentry. בדיקה אחת השאירה SENTRY_DSN בסביבה, ו-tests/test_lock_cleanup_guard.py — ואחריו כל בדיקה שטוענת מחדש את main — הדליק ממנו לקוח אמיתי בתוך תהליך הבדיקות, מכוון לשרתי sentry.io. בסוף ריצה כזו נראתה השורה Sentry is attempting to send 2 pending events. לא בדקתי אם אירועים באמת יצאו מה-CI. את הצד של הבדיקות סוגר PR נפרד (שומר שמכשיל בדיקה שמשאירה את Sentry דלוק); הצד של קוד הייצור נשאר, והוא האישו הזה.
הצעה לתיקון
לפי bugbot-rules/import-time-side-effects.md (ב-amir-bug-patterns), סעיף 2 — בניית לקוח ברמת המודול מתוך קונפיג גלובלי: ברמה העליונה רק הגדרות. init_sentry() נקרא במפורש מנקודת הכניסה של כל שירות שצריך אותו — main() של הבוט, ההפעלה של שרת ה-aiohttp, ה-factory או ההפעלה של הוובאפ — ולא מייבוא.
מה צריך לבדוק לפני
- איך כל שירות מופעל בפרודקשן.
render.yaml מגדיר רק את Prometheus ואת Alertmanager, כך שפקודות ההפעלה של הבוט, הוובאפ ושרת ה-MCP לא נמצאות בריפו. צריך לוודא שבכל אחד מהם הקריאה החדשה רצה מוקדם מספיק — Sentry שמאותחל מאוחר מפספס שגיאות עלייה.
- מי מייבא את
main או את services/webserver.py ונשען על כך שהייבוא מדליק את Sentry. ייתכן שיש שירות שלא קורא ל-init_sentry בעצמו ומקבל אותו בחינם מהייבוא.
מה קורה
שלושה מודולים מדליקים לקוח Sentry כבר כשמייבאים אותם, בלי שאף נקודת כניסה ביקשה:
main.py— קורא ל-init_sentry()ברמה העליונה של המודול (בתוךtry), מיד אחריsetup_structlog_logging.services/webserver.py— אותו דבר, ב-tryשבראש הקובץ.webapp/app.py—sentry_sdk.init(...)ברמת המודול, תחתif _SENTRY_AVAILABLE and config.SENTRY_DSN.init_sentry(observability.py) לוקח את הכתובת מ-SENTRY_DSNבסביבה, ואם אין — מ-config.SENTRY_DSN. כלומר כל ייבוא שלmain— טסט, סקריפט שצריך פונקציה אחת,importlib.reload— בונה לקוח שמדבר עם הרשת, עם כל האינטגרציות ש-sentry-sdk מדליק לבד כשהספרייה שלהן מותקנת (auto_enabling_integrations, ברירת המחדל). נמדד בתהליך הבדיקות, על sentry-sdk 2.42.1: אחריimportlib.reload(main)עםSENTRY_DSNבסביבה, הלקוח עלה עם 14 אינטגרציות — ביניהן starlette, pymongo, redis, httpx, aiohttp ו-flask — והן עוטפות את הספריות האלה עד סוף התהליך.איך זה נשך
זה מה שהפך
importlib.reload(main)בבדיקות למתג של Sentry. בדיקה אחת השאירהSENTRY_DSNבסביבה, ו-tests/test_lock_cleanup_guard.py— ואחריו כל בדיקה שטוענת מחדש אתmain— הדליק ממנו לקוח אמיתי בתוך תהליך הבדיקות, מכוון לשרתי sentry.io. בסוף ריצה כזו נראתה השורהSentry is attempting to send 2 pending events. לא בדקתי אם אירועים באמת יצאו מה-CI. את הצד של הבדיקות סוגר PR נפרד (שומר שמכשיל בדיקה שמשאירה את Sentry דלוק); הצד של קוד הייצור נשאר, והוא האישו הזה.הצעה לתיקון
לפי
bugbot-rules/import-time-side-effects.md(ב-amir-bug-patterns), סעיף 2 — בניית לקוח ברמת המודול מתוך קונפיג גלובלי: ברמה העליונה רק הגדרות.init_sentry()נקרא במפורש מנקודת הכניסה של כל שירות שצריך אותו —main()של הבוט, ההפעלה של שרת ה-aiohttp, ה-factory או ההפעלה של הוובאפ — ולא מייבוא.מה צריך לבדוק לפני
render.yamlמגדיר רק את Prometheus ואת Alertmanager, כך שפקודות ההפעלה של הבוט, הוובאפ ושרת ה-MCP לא נמצאות בריפו. צריך לוודא שבכל אחד מהם הקריאה החדשה רצה מוקדם מספיק — Sentry שמאותחל מאוחר מפספס שגיאות עלייה.mainאו אתservices/webserver.pyונשען על כך שהייבוא מדליק את Sentry. ייתכן שיש שירות שלא קורא ל-init_sentryבעצמו ומקבל אותו בחינם מהייבוא.