Upload 12 files
Browse files
src/agentcore/orchestrator.py
CHANGED
|
@@ -185,13 +185,27 @@ def analytics_log_status() -> dict:
|
|
| 185 |
|
| 186 |
|
| 187 |
async def _send_log_payload(worker_url: str, token: str, payload: dict):
|
| 188 |
-
"""POST one analytics payload.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
from src.services.http_client import make_client as _mk
|
| 190 |
headers = {"Authorization": f"Bearer {token}"} if token else {}
|
| 191 |
async with _mk(timeout=10) as client:
|
| 192 |
resp = await client.post(worker_url.rstrip("/") + "/log",
|
| 193 |
json=payload, headers=headers)
|
| 194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
|
| 196 |
|
| 197 |
async def _flush_pending(worker_url: str, token: str, max_items: int = 5):
|
|
@@ -201,10 +215,10 @@ async def _flush_pending(worker_url: str, token: str, max_items: int = 5):
|
|
| 201 |
while _PENDING_LOGS and sent < max_items:
|
| 202 |
payload = _PENDING_LOGS[0]
|
| 203 |
try:
|
| 204 |
-
status = await _send_log_payload(worker_url, token, payload)
|
| 205 |
except Exception:
|
| 206 |
return sent
|
| 207 |
-
if status >= 400:
|
| 208 |
return sent
|
| 209 |
_PENDING_LOGS.popleft()
|
| 210 |
sent += 1
|
|
@@ -258,7 +272,7 @@ def _log_agent_query(question: str, response: AgentResponse, start_time: float)
|
|
| 258 |
except Exception:
|
| 259 |
pass
|
| 260 |
try:
|
| 261 |
-
status = await _send_log_payload(worker_url, _token, _payload)
|
| 262 |
except Exception as _exc:
|
| 263 |
_PENDING_LOGS.append(_payload)
|
| 264 |
_record_attempt("unreachable", f"{type(_exc).__name__}: {_exc}")
|
|
@@ -286,8 +300,22 @@ def _log_agent_query(question: str, response: AgentResponse, start_time: float)
|
|
| 286 |
_PENDING_LOGS.append(_payload)
|
| 287 |
_record_attempt("http_error", f"HTTP {status}")
|
| 288 |
logger.warning(f"D1 logging failed: HTTP {status}; buffered")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
else:
|
| 290 |
-
_record_attempt("ok", f"HTTP {status}")
|
| 291 |
logger.debug("D1 logged OK")
|
| 292 |
|
| 293 |
if not _spawn_background(_post_to_worker()):
|
|
|
|
| 185 |
|
| 186 |
|
| 187 |
async def _send_log_payload(worker_url: str, token: str, payload: dict):
|
| 188 |
+
"""POST one analytics payload.
|
| 189 |
+
|
| 190 |
+
Returns (status_code, report) where report is the Worker's own JSON verdict.
|
| 191 |
+
This matters because the Worker answers HTTP 200 even when the D1 INSERT
|
| 192 |
+
itself failed, reporting the problem in a 'warning' field - so a status code
|
| 193 |
+
alone cannot distinguish a stored row from a dropped one.
|
| 194 |
+
"""
|
| 195 |
from src.services.http_client import make_client as _mk
|
| 196 |
headers = {"Authorization": f"Bearer {token}"} if token else {}
|
| 197 |
async with _mk(timeout=10) as client:
|
| 198 |
resp = await client.post(worker_url.rstrip("/") + "/log",
|
| 199 |
json=payload, headers=headers)
|
| 200 |
+
report = {}
|
| 201 |
+
try:
|
| 202 |
+
body = resp.json()
|
| 203 |
+
if isinstance(body, dict):
|
| 204 |
+
report = {k: body.get(k) for k in ("status", "logged", "schema", "warning")
|
| 205 |
+
if body.get(k) is not None}
|
| 206 |
+
except Exception:
|
| 207 |
+
report = {"raw": resp.text[:120]}
|
| 208 |
+
return resp.status_code, report
|
| 209 |
|
| 210 |
|
| 211 |
async def _flush_pending(worker_url: str, token: str, max_items: int = 5):
|
|
|
|
| 215 |
while _PENDING_LOGS and sent < max_items:
|
| 216 |
payload = _PENDING_LOGS[0]
|
| 217 |
try:
|
| 218 |
+
status, report = await _send_log_payload(worker_url, token, payload)
|
| 219 |
except Exception:
|
| 220 |
return sent
|
| 221 |
+
if status >= 400 or report.get("logged") is False:
|
| 222 |
return sent
|
| 223 |
_PENDING_LOGS.popleft()
|
| 224 |
sent += 1
|
|
|
|
| 272 |
except Exception:
|
| 273 |
pass
|
| 274 |
try:
|
| 275 |
+
status, report = await _send_log_payload(worker_url, _token, _payload)
|
| 276 |
except Exception as _exc:
|
| 277 |
_PENDING_LOGS.append(_payload)
|
| 278 |
_record_attempt("unreachable", f"{type(_exc).__name__}: {_exc}")
|
|
|
|
| 300 |
_PENDING_LOGS.append(_payload)
|
| 301 |
_record_attempt("http_error", f"HTTP {status}")
|
| 302 |
logger.warning(f"D1 logging failed: HTTP {status}; buffered")
|
| 303 |
+
elif report.get("logged") is False:
|
| 304 |
+
# Worker answered 200 but told us the row was not stored.
|
| 305 |
+
_PENDING_LOGS.append(_payload)
|
| 306 |
+
_record_attempt("worker_rejected",
|
| 307 |
+
f"HTTP {status} {report.get('warning') or report}")
|
| 308 |
+
logger.warning(
|
| 309 |
+
f"D1 insert failed Worker-side: {report.get('warning') or report}"
|
| 310 |
+
)
|
| 311 |
+
elif report.get("warning"):
|
| 312 |
+
# Stored, but via the legacy fallback schema - surface it.
|
| 313 |
+
_record_attempt("ok_with_warning",
|
| 314 |
+
f"HTTP {status} schema={report.get('schema')} "
|
| 315 |
+
f"{report.get('warning')}")
|
| 316 |
+
logger.warning(f"D1 logged with warning: {report.get('warning')}")
|
| 317 |
else:
|
| 318 |
+
_record_attempt("ok", f"HTTP {status} schema={report.get('schema')}")
|
| 319 |
logger.debug("D1 logged OK")
|
| 320 |
|
| 321 |
if not _spawn_background(_post_to_worker()):
|