-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathactivity_reporter.py
More file actions
136 lines (123 loc) · 5.06 KB
/
Copy pathactivity_reporter.py
File metadata and controls
136 lines (123 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
"""
קובץ פשוט לדיווח פעילות - העתק את הקובץ הזה לכל בוט
"""
try:
from pymongo import MongoClient # type: ignore
_HAS_PYMONGO = True
except Exception:
MongoClient = None # type: ignore
_HAS_PYMONGO = False
from datetime import datetime, timezone
import atexit
# חיבור MongoDB גלובלי יחיד לכל האפליקציה
_client = None # type: ignore
_owns_client = False # האם המודול יצר את הלקוח בעצמו
def get_mongo_client(mongodb_uri: str):
"""החזרת מופע MongoClient יחיד (singleton) לכל האפליקציה.
בכל קריאה מחזיר את אותו אובייקט, ויוצר רק בפעם הראשונה.
"""
global _client
if not _HAS_PYMONGO:
raise RuntimeError("pymongo not available")
if _client is None:
# אם כבר קיים לקוח במסד הנתונים המרכזי – נמחזר אותו, כדי למנוע כפילויות
try:
from database import db as _db # import דינמי כדי להימנע מייבוא מעגלי בזמן טעינה
existing = getattr(_db, "client", None)
except Exception:
existing = None
if existing is not None:
# שימוש בלקוח קיים של המערכת (לא אנחנו יוצרים/סוגרים)
_client = existing
globals()["_owns_client"] = False
else:
# יצירת לקוח משלנו עם timezone-aware
_client = MongoClient(mongodb_uri, tz_aware=True, tzinfo=timezone.utc)
globals()["_owns_client"] = True
return _client
def close_mongo_client() -> None:
"""סגירת החיבור הגלובלי בבטחה בזמן כיבוי השירות."""
global _client
try:
if _client is not None and globals().get("_owns_client", False):
_client.close()
finally:
_client = None
# סגירה אוטומטית ביציאה מהתהליך
atexit.register(close_mongo_client)
try:
from metrics import note_active_user # type: ignore
except Exception: # pragma: no cover
def note_active_user(user_id: int) -> None: # type: ignore
return None
class SimpleActivityReporter:
def __init__(self, mongodb_uri, service_id, service_name=None):
"""
mongodb_uri: חיבור למונגו (אותו מהבוט המרכזי)
service_id: מזהה השירות ב-Render
service_name: שם הבוט (אופציונלי)
"""
try:
if not _HAS_PYMONGO:
raise RuntimeError("pymongo not available")
# שימוש ב-singleton של MongoClient כדי למנוע חיבורים מרובים
self.client = get_mongo_client(mongodb_uri)
self.db = self.client["render_bot_monitor"]
self.service_id = service_id
self.service_name = service_name or service_id
self.connected = True
except Exception:
self.connected = False
# שקט בסביבת בדיקות/ללא pymongo
pass
def report_activity(self, user_id):
"""דיווח פעילות פשוט"""
if not self.connected:
try:
# Even if DB is unavailable, update in-memory active users gauge if possible
note_active_user(int(user_id))
except Exception:
pass
return
try:
now = datetime.now(timezone.utc)
# עדכון אינטראקציית המשתמש
self.db.user_interactions.update_one(
{"service_id": self.service_id, "user_id": user_id},
{
"$set": {"last_interaction": now},
"$inc": {"interaction_count": 1},
"$setOnInsert": {"created_at": now}
},
upsert=True
)
# עדכון פעילות השירות
self.db.service_activity.update_one(
{"_id": self.service_id},
{
"$set": {
"last_user_activity": now,
"service_name": self.service_name,
"updated_at": now
},
"$setOnInsert": {
"created_at": now,
"status": "active",
"total_users": 0,
"suspend_count": 0
}
},
upsert=True
)
# Update active users gauge
try:
note_active_user(int(user_id))
except Exception:
pass
except Exception:
# שקט - אל תיכשל את הבוט אם יש בעיה
pass
# דוגמה לשימוש קל
def create_reporter(mongodb_uri, service_id, service_name=None):
"""יצירת reporter פשוט"""
return SimpleActivityReporter(mongodb_uri, service_id, service_name)