Spaces:
Running
Running
sync: 193 file da Baida98/AI@6dc5684d (2026-08-27 21:57 UTC) [deploy-all]
#126
by Baida07 - opened
- api/performance_rum.py +63 -37
api/performance_rum.py
CHANGED
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
| 11 |
|
| 12 |
import asyncio
|
| 13 |
import hashlib
|
|
|
|
| 14 |
import math
|
| 15 |
import os
|
| 16 |
import re
|
|
@@ -37,6 +38,7 @@ _ALLOWED_NAVIGATION = frozenset({"navigate", "reload", "back-forward", "prerende
|
|
| 37 |
_RATE_WINDOW_SECONDS = 60
|
| 38 |
_RATE_LIMIT = 120
|
| 39 |
_rate_buckets: dict[str, tuple[float, int]] = {}
|
|
|
|
| 40 |
|
| 41 |
|
| 42 |
class MetricSample(BaseModel):
|
|
@@ -148,24 +150,36 @@ async def ingest_metric(
|
|
| 148 |
if not _allow_rate(_rate_key(request, os.getenv("RUM_HASH_SALT", "rum"))):
|
| 149 |
raise HTTPException(status_code=429, detail="rate limit exceeded")
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
return {"accepted": True}
|
| 170 |
|
| 171 |
|
|
@@ -183,25 +197,37 @@ async def performance_summary(
|
|
| 183 |
if release != "all" and not _RELEASE_RE.fullmatch(release.lower()):
|
| 184 |
raise HTTPException(status_code=400, detail="invalid release")
|
| 185 |
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
for row in rows:
|
| 206 |
if row["sample_count"] < 20:
|
| 207 |
row["p50"] = row["p75"] = row["p95"] = None
|
|
|
|
| 11 |
|
| 12 |
import asyncio
|
| 13 |
import hashlib
|
| 14 |
+
import logging
|
| 15 |
import math
|
| 16 |
import os
|
| 17 |
import re
|
|
|
|
| 38 |
_RATE_WINDOW_SECONDS = 60
|
| 39 |
_RATE_LIMIT = 120
|
| 40 |
_rate_buckets: dict[str, tuple[float, int]] = {}
|
| 41 |
+
_logger = logging.getLogger("performance_rum")
|
| 42 |
|
| 43 |
|
| 44 |
class MetricSample(BaseModel):
|
|
|
|
| 150 |
if not _allow_rate(_rate_key(request, os.getenv("RUM_HASH_SALT", "rum"))):
|
| 151 |
raise HTTPException(status_code=429, detail="rate limit exceeded")
|
| 152 |
|
| 153 |
+
try:
|
| 154 |
+
await asyncio.to_thread(
|
| 155 |
+
_execute,
|
| 156 |
+
"""
|
| 157 |
+
insert into public.rum_samples
|
| 158 |
+
(metric, value, release, device, connection_type, navigation_type, bucket_start)
|
| 159 |
+
values (%(metric)s, %(value)s, %(release)s, %(device)s, %(connection_type)s,
|
| 160 |
+
%(navigation_type)s, %(bucket_start)s)
|
| 161 |
+
""",
|
| 162 |
+
{
|
| 163 |
+
"metric": sample.metric,
|
| 164 |
+
"value": sample.value,
|
| 165 |
+
"release": sample.release,
|
| 166 |
+
"device": sample.device,
|
| 167 |
+
"connection_type": sample.connection_type,
|
| 168 |
+
"navigation_type": sample.navigation_type,
|
| 169 |
+
"bucket_start": _bucket_start(datetime.now(timezone.utc)),
|
| 170 |
+
},
|
| 171 |
+
)
|
| 172 |
+
except HTTPException:
|
| 173 |
+
raise
|
| 174 |
+
except Exception as exc:
|
| 175 |
+
_logger.error(
|
| 176 |
+
"RUM database operation failed type=%s metric=%s device=%s",
|
| 177 |
+
type(exc).__name__, sample.metric, sample.device,
|
| 178 |
+
)
|
| 179 |
+
raise HTTPException(
|
| 180 |
+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
| 181 |
+
detail="RUM database temporaneamente non disponibile",
|
| 182 |
+
) from exc
|
| 183 |
return {"accepted": True}
|
| 184 |
|
| 185 |
|
|
|
|
| 197 |
if release != "all" and not _RELEASE_RE.fullmatch(release.lower()):
|
| 198 |
raise HTTPException(status_code=400, detail="invalid release")
|
| 199 |
|
| 200 |
+
try:
|
| 201 |
+
rows = await asyncio.to_thread(
|
| 202 |
+
_execute,
|
| 203 |
+
"""
|
| 204 |
+
select metric, release, device,
|
| 205 |
+
count(*)::integer as sample_count,
|
| 206 |
+
percentile_cont(0.50) within group (order by value) as p50,
|
| 207 |
+
percentile_cont(0.75) within group (order by value) as p75,
|
| 208 |
+
percentile_cont(0.95) within group (order by value) as p95
|
| 209 |
+
from public.rum_samples
|
| 210 |
+
where bucket_start >= %(from_time)s
|
| 211 |
+
and bucket_start < %(to_time)s
|
| 212 |
+
and device = %(device)s
|
| 213 |
+
and (%(release)s = 'all' or release = %(release)s)
|
| 214 |
+
group by metric, release, device
|
| 215 |
+
order by metric, release
|
| 216 |
+
""",
|
| 217 |
+
{"from_time": from_time, "to_time": to_time, "device": device, "release": release.lower()},
|
| 218 |
+
fetch=True,
|
| 219 |
+
)
|
| 220 |
+
except HTTPException:
|
| 221 |
+
raise
|
| 222 |
+
except Exception as exc:
|
| 223 |
+
_logger.error(
|
| 224 |
+
"RUM summary database operation failed type=%s device=%s",
|
| 225 |
+
type(exc).__name__, device,
|
| 226 |
+
)
|
| 227 |
+
raise HTTPException(
|
| 228 |
+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
| 229 |
+
detail="RUM database temporaneamente non disponibile",
|
| 230 |
+
) from exc
|
| 231 |
for row in rows:
|
| 232 |
if row["sample_count"] < 20:
|
| 233 |
row["p50"] = row["p75"] = row["p95"] = None
|