Spaces:
Runtime error
Runtime error
add timeout supabase
Browse files- core/supabase_sync_service.py +35 -12
core/supabase_sync_service.py
CHANGED
|
@@ -4,6 +4,7 @@ import logging
|
|
| 4 |
import os
|
| 5 |
import re
|
| 6 |
import tempfile
|
|
|
|
| 7 |
from datetime import datetime, timezone
|
| 8 |
from typing import Any, Dict, List, Optional
|
| 9 |
from urllib import error, parse, request
|
|
@@ -320,6 +321,8 @@ class SupabaseStorageSyncService:
|
|
| 320 |
) from http_error
|
| 321 |
except error.URLError as url_error:
|
| 322 |
raise RuntimeError(f"Supabase connection error at {endpoint}: {url_error.reason}") from url_error
|
|
|
|
|
|
|
| 323 |
|
| 324 |
@staticmethod
|
| 325 |
def _encode_object_path(object_path: str) -> str:
|
|
@@ -494,18 +497,38 @@ class SupabaseSyncCoordinator:
|
|
| 494 |
|
| 495 |
def _execute_sync_cycle(self, trigger: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
| 496 |
del payload
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 509 |
|
| 510 |
def _apply_incremental_changes(self, scan_result: Dict[str, Any]) -> Dict[str, int]:
|
| 511 |
added_rows = [row for row in (scan_result.get("added") or []) if isinstance(row, dict)]
|
|
|
|
| 4 |
import os
|
| 5 |
import re
|
| 6 |
import tempfile
|
| 7 |
+
import time
|
| 8 |
from datetime import datetime, timezone
|
| 9 |
from typing import Any, Dict, List, Optional
|
| 10 |
from urllib import error, parse, request
|
|
|
|
| 321 |
) from http_error
|
| 322 |
except error.URLError as url_error:
|
| 323 |
raise RuntimeError(f"Supabase connection error at {endpoint}: {url_error.reason}") from url_error
|
| 324 |
+
except TimeoutError as timeout_error:
|
| 325 |
+
raise RuntimeError(f"Supabase request timed out at {endpoint} (>{self.timeout_seconds}s): {timeout_error}") from timeout_error
|
| 326 |
|
| 327 |
@staticmethod
|
| 328 |
def _encode_object_path(object_path: str) -> str:
|
|
|
|
| 497 |
|
| 498 |
def _execute_sync_cycle(self, trigger: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
| 499 |
del payload
|
| 500 |
+
max_retries = 3
|
| 501 |
+
retry_backoff_seconds = 2
|
| 502 |
+
|
| 503 |
+
last_error = None
|
| 504 |
+
for attempt in range(max_retries):
|
| 505 |
+
try:
|
| 506 |
+
scan_result = self.sync_service.scan_and_diff_snapshot()
|
| 507 |
+
apply_result = self._apply_incremental_changes(scan_result)
|
| 508 |
+
|
| 509 |
+
return {
|
| 510 |
+
"trigger": trigger,
|
| 511 |
+
"total_folders": int(scan_result.get("total_folders", 0)),
|
| 512 |
+
"total_objects": int(scan_result.get("total_objects", 0)),
|
| 513 |
+
"added": int(apply_result.get("added", 0)),
|
| 514 |
+
"updated": int(apply_result.get("updated", 0)),
|
| 515 |
+
"deleted": int(apply_result.get("deleted", 0)),
|
| 516 |
+
"failed": int(apply_result.get("failed", 0)),
|
| 517 |
+
}
|
| 518 |
+
except RuntimeError as error:
|
| 519 |
+
last_error = error
|
| 520 |
+
if "timed out" in str(error).lower() and attempt < max_retries - 1:
|
| 521 |
+
wait_time = retry_backoff_seconds * (2 ** attempt)
|
| 522 |
+
logger.warning(
|
| 523 |
+
f"Supabase sync timeout on attempt {attempt + 1}/{max_retries}. "
|
| 524 |
+
f"Retrying in {wait_time}s... Error: {error}"
|
| 525 |
+
)
|
| 526 |
+
time.sleep(wait_time)
|
| 527 |
+
continue
|
| 528 |
+
raise
|
| 529 |
+
|
| 530 |
+
if last_error:
|
| 531 |
+
raise last_error
|
| 532 |
|
| 533 |
def _apply_incremental_changes(self, scan_result: Dict[str, Any]) -> Dict[str, int]:
|
| 534 |
added_rows = [row for row in (scan_result.get("added") or []) if isinstance(row, dict)]
|