light poller commit3

This commit is contained in:
Mateusz Gruszczyński
2026-05-27 15:13:22 +02:00
parent 054c9122f8
commit a8adee0f2f
6 changed files with 143 additions and 4 deletions

View File

@@ -126,6 +126,24 @@ class ProfilePollState:
skipped_emissions: int = 0
emitted_payload_size: int = 0
rtorrent_call_count: int = 0
live_poll_count: int = 0
list_poll_count: int = 0
live_updated_total: int = 0
live_full_refresh_requested_total: int = 0
list_added_total: int = 0
list_updated_total: int = 0
list_removed_total: int = 0
last_live_duration_ms: float = 0.0
last_list_duration_ms: float = 0.0
last_live_updated_count: int = 0
last_list_added_count: int = 0
last_list_updated_count: int = 0
last_list_removed_count: int = 0
last_live_ok: bool = True
last_list_ok: bool = True
last_live_error: str = ""
last_list_error: str = ""
last_live_requires_full_refresh: bool = False
adaptive_mode: str = "normal"
slow_task_running: bool = False
system_task_running: bool = False
@@ -206,6 +224,69 @@ def should_heartbeat(now: float, settings: dict, state: ProfilePollState, change
return (now - state.last_heartbeat_at) >= float(settings["heartbeat_interval_seconds"])
def mark_live_poll(state: ProfilePollState, started_at: float, ok: bool, error: str = "", updated_count: int = 0, requires_full_refresh: bool = False) -> None:
now = time.monotonic()
# Note: Live poller diagnostics track only lightweight speed/status refreshes, not the full torrent snapshot loop.
state.live_poll_count += 1
state.last_live_duration_ms = round((now - started_at) * 1000.0, 2)
state.last_live_updated_count = int(updated_count or 0)
state.live_updated_total += int(updated_count or 0)
state.last_live_requires_full_refresh = bool(requires_full_refresh)
if requires_full_refresh:
state.live_full_refresh_requested_total += 1
state.last_live_ok = bool(ok)
state.last_live_error = str(error or "")
def mark_list_poll(state: ProfilePollState, started_at: float, ok: bool, error: str = "", added_count: int = 0, updated_count: int = 0, removed_count: int = 0) -> None:
now = time.monotonic()
# Note: List poller diagnostics are separate because this slower loop runs full torrent snapshot reconciliation.
state.list_poll_count += 1
state.last_list_duration_ms = round((now - started_at) * 1000.0, 2)
state.last_list_added_count = int(added_count or 0)
state.last_list_updated_count = int(updated_count or 0)
state.last_list_removed_count = int(removed_count or 0)
state.list_added_total += int(added_count or 0)
state.list_updated_total += int(updated_count or 0)
state.list_removed_total += int(removed_count or 0)
state.last_list_ok = bool(ok)
state.last_list_error = str(error or "")
def reset_runtime_stats(profile_id: int) -> dict:
state = state_for(profile_id)
# Note: Cleanup resets diagnostic counters only; poller timers and saved settings keep running unchanged.
state.tick_count = 0
state.last_tick_ms = 0.0
state.last_tick_gap_ms = 0.0
state.last_tick_started_at = 0.0
state.error_count = 0
state.slow_count = 0
state.skipped_emissions = 0
state.emitted_payload_size = 0
state.rtorrent_call_count = 0
state.live_poll_count = 0
state.list_poll_count = 0
state.live_updated_total = 0
state.live_full_refresh_requested_total = 0
state.list_added_total = 0
state.list_updated_total = 0
state.list_removed_total = 0
state.last_live_duration_ms = 0.0
state.last_list_duration_ms = 0.0
state.last_live_updated_count = 0
state.last_list_added_count = 0
state.last_list_updated_count = 0
state.last_list_removed_count = 0
state.last_live_ok = True
state.last_list_ok = True
state.last_live_error = ""
state.last_list_error = ""
state.last_live_requires_full_refresh = False
state.stats = {}
return snapshot(profile_id)
def mark_tick(state: ProfilePollState, started_at: float, active: bool, ok: bool, error: str = "", emitted_payload_size: int = 0, rtorrent_call_count: int = 0, skipped_emissions: int = 0, settings: dict | None = None) -> dict:
now = time.monotonic()
effective_settings = normalize_settings(settings) if settings is not None else DEFAULTS
@@ -267,6 +348,24 @@ def mark_tick(state: ProfilePollState, started_at: float, active: bool, ok: bool
"adaptive_mode": state.adaptive_mode,
"error_count": state.error_count,
"slow_count": state.slow_count,
"live_poll_count": state.live_poll_count,
"list_poll_count": state.list_poll_count,
"last_live_duration_ms": state.last_live_duration_ms,
"last_list_duration_ms": state.last_list_duration_ms,
"last_live_updated_count": state.last_live_updated_count,
"last_list_added_count": state.last_list_added_count,
"last_list_updated_count": state.last_list_updated_count,
"last_list_removed_count": state.last_list_removed_count,
"live_updated_total": state.live_updated_total,
"list_added_total": state.list_added_total,
"list_updated_total": state.list_updated_total,
"list_removed_total": state.list_removed_total,
"live_full_refresh_requested_total": state.live_full_refresh_requested_total,
"last_live_requires_full_refresh": state.last_live_requires_full_refresh,
"last_live_ok": state.last_live_ok,
"last_list_ok": state.last_list_ok,
"last_live_error": state.last_live_error,
"last_list_error": state.last_list_error,
"updated_at": utcnow(),
}
return dict(state.stats)
@@ -274,4 +373,26 @@ def mark_tick(state: ProfilePollState, started_at: float, active: bool, ok: bool
def snapshot(profile_id: int) -> dict:
state = state_for(profile_id)
return dict(state.stats or {"profile_id": int(profile_id), "tick_count": state.tick_count})
data = dict(state.stats or {"profile_id": int(profile_id), "tick_count": state.tick_count})
# Note: Snapshot always exposes split-poller counters, even before the first post-cleanup tick rebuilds full stats.
data.update({
"live_poll_count": state.live_poll_count,
"list_poll_count": state.list_poll_count,
"last_live_duration_ms": state.last_live_duration_ms,
"last_list_duration_ms": state.last_list_duration_ms,
"last_live_updated_count": state.last_live_updated_count,
"last_list_added_count": state.last_list_added_count,
"last_list_updated_count": state.last_list_updated_count,
"last_list_removed_count": state.last_list_removed_count,
"live_updated_total": state.live_updated_total,
"list_added_total": state.list_added_total,
"list_updated_total": state.list_updated_total,
"list_removed_total": state.list_removed_total,
"live_full_refresh_requested_total": state.live_full_refresh_requested_total,
"last_live_requires_full_refresh": state.last_live_requires_full_refresh,
"last_live_ok": state.last_live_ok,
"last_list_ok": state.last_list_ok,
"last_live_error": state.last_live_error,
"last_list_error": state.last_list_error,
})
return data