-
Notifications
You must be signed in to change notification settings - Fork 17
GML-2163-UI-GAP: surface rebuild stage in UI during long ECC phases - add progres… #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release_2.0.1
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,6 +62,10 @@ | |
| from common.metrics.prometheus_metrics import metrics as pmetrics | ||
| from common.metrics.tg_proxy import TigerGraphConnectionProxy | ||
| from common.utils.graph_locks import acquire_graph_lock, release_graph_lock, acquire_rebuild_lock, release_rebuild_lock, get_rebuilding_graph, get_current_operation | ||
|
|
||
| # Cache the last successful ECC status response per graph so the UI | ||
| # still sees started_at and stage when ECC is too busy to respond. | ||
| _last_ecc_status_cache: dict = {} | ||
| from supportai import supportai | ||
| from common.py_schemas.schemas import ( | ||
| AgentProgess, | ||
|
|
@@ -2258,7 +2262,7 @@ async def rebuild_and_monitor(): | |
| elapsed = 0 | ||
|
|
||
| while elapsed < max_wait_time: | ||
| await asyncio.sleep(poll_interval) # Non-blocking sleep | ||
| await asyncio.sleep(poll_interval) | ||
| elapsed += poll_interval | ||
|
|
||
| try: | ||
|
|
@@ -2272,6 +2276,11 @@ async def rebuild_and_monitor(): | |
| status_data = status_response.json() | ||
| is_running = status_data.get("is_running", False) | ||
| status = status_data.get("status", "unknown") | ||
|
|
||
| # Cache last known good response so the UI endpoint | ||
| # can fall back to it when ECC is too busy to respond. | ||
| if is_running and status_data.get("started_at"): | ||
| _last_ecc_status_cache[graphname] = status_data | ||
|
|
||
| # Log every minute to avoid spam | ||
| if elapsed % 60 == 0: | ||
|
|
@@ -2280,6 +2289,7 @@ async def rebuild_and_monitor(): | |
| # Check if ALL stages are complete | ||
| if not is_running and status in ["completed", "failed", "idle"]: | ||
| LogWriter.info(f"ECC rebuild finished for {graphname} with status: {status} after {elapsed}s") | ||
| _last_ecc_status_cache.pop(graphname, None) | ||
| break | ||
| else: | ||
| LogWriter.warning(f"ECC status check returned {status_response.status_code} for {graphname}") | ||
|
|
@@ -2290,12 +2300,17 @@ async def rebuild_and_monitor(): | |
|
|
||
| if elapsed >= max_wait_time: | ||
| LogWriter.error(f"ECC rebuild monitoring timed out for {graphname} after {max_wait_time}s") | ||
| _last_ecc_status_cache.pop(graphname, None) | ||
|
|
||
| except Exception as e: | ||
| LogWriter.error(f"Error during ECC rebuild monitoring for {graphname}: {e}") | ||
|
Comment on lines
2305
to
2306
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: New proposed code: except Exception as e:
LogWriter.error(f"Error during ECC rebuild monitoring for {graphname}: {e}")
import traceback
LogWriter.error(traceback.format_exc())
finally:
+ _last_ecc_status_cache.pop(graphname, None)
# Release lock only after ALL stages complete (or timeout/error)
release_rebuild_lock(graphname)
LogWriter.info(f"Released global rebuild lock for {graphname}") |
||
| import traceback | ||
| LogWriter.error(traceback.format_exc()) | ||
| finally: | ||
| # Always drop cached status when monitoring ends (success, | ||
| # timeout, or unexpected failure) so timeout fallbacks do | ||
| # not keep reporting a stale rebuild as active. | ||
| _last_ecc_status_cache.pop(graphname, None) | ||
| # Release lock only after ALL stages complete (or timeout/error) | ||
| release_rebuild_lock(graphname) | ||
| LogWriter.info(f"Released global rebuild lock for {graphname}") | ||
|
|
@@ -2342,12 +2357,15 @@ def get_rebuild_status( | |
| "error": f"ECC service returned status {response.status_code}" | ||
| } | ||
| except httpx.TimeoutException as e: | ||
| # ECC is busy (heavy processing) - assume rebuild is still running | ||
| # ECC is busy (heavy processing) - assume rebuild is still running. | ||
| # Return the last cached status so the UI keeps started_at and stage. | ||
| LogWriter.warning(f"ECC status check timed out (ECC may be busy): {str(e)}") | ||
| cached = _last_ecc_status_cache.get(graphname, {}) | ||
| return { | ||
| **cached, | ||
| "graphname": graphname, | ||
| "is_running": True, | ||
| "status": "unknown", | ||
| "status": cached.get("status", "unknown"), | ||
| "error": "ECC is busy processing, status check timed out. Rebuild likely still in progress." | ||
| } | ||
| except Exception as e: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: If
progressis an async callback, calling it without awaiting will silently skip the UI update and emit an un-awaited coroutine warning. Capture the return value and await it when it is a coroutine; apply the same pattern to the newprogress(...)calls inextractandsummarize_communities. [possible issue, importance: 6]