fix: window_timeout for one-shot tasks, drop debug stderr logging
_poll_task now accepts window_timeout. For DirSize and MD5 (one-shot result windows), if only 599 errors arrive for window_timeout seconds without ever seeing the task alive (finished=False), return a fast "result window missed — please retry" error instead of waiting the full 60 s. Tasks that return finished=False at least once (large dirs, large files) are unaffected. Also removes the stale [dsm] debug stderr.write left in client.request(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
"""MCP server for Synology FileStation."""
|
||||
|
||||
__version__ = "0.2.4"
|
||||
__version__ = "0.2.5"
|
||||
|
||||
@@ -247,8 +247,6 @@ class FileStationClient:
|
||||
Raises:
|
||||
SynologyError: On API errors.
|
||||
"""
|
||||
sys.stderr.write(f"[dsm] request: {api}/{method}\n")
|
||||
sys.stderr.flush()
|
||||
if not self._initializing:
|
||||
await self._ensure_initialized()
|
||||
http = self._get_http()
|
||||
|
||||
@@ -66,6 +66,7 @@ def register_filestation(
|
||||
version: int,
|
||||
taskid: str,
|
||||
initial_delay: float = 0.2,
|
||||
window_timeout: float | None = None,
|
||||
) -> tuple[bool, dict[str, Any] | str]:
|
||||
"""Poll a DSM async task until finished or timeout.
|
||||
|
||||
@@ -76,6 +77,11 @@ def register_filestation(
|
||||
initial_delay: Seconds to wait before the first status poll.
|
||||
Set to 0.0 for tasks that may finish before the first poll
|
||||
interval (e.g. DirSize on small directories, MD5 on small files).
|
||||
window_timeout: For one-shot tasks (DirSize, MD5) whose result is
|
||||
available exactly once: if we receive nothing but 599 errors for
|
||||
this many seconds without ever seeing the task running
|
||||
(``finished=False``), the result window was missed — return an
|
||||
error immediately instead of waiting for the full 60 s timeout.
|
||||
|
||||
Returns:
|
||||
``(True, status_dict)`` on success, or ``(False, "Error: …")`` on
|
||||
@@ -86,6 +92,7 @@ def register_filestation(
|
||||
delay = 0.2
|
||||
elapsed = initial_delay
|
||||
timeout = 60.0
|
||||
seen_task_alive = False # True once we receive any non-599 status response
|
||||
|
||||
if initial_delay > 0:
|
||||
await asyncio.sleep(initial_delay)
|
||||
@@ -100,13 +107,25 @@ def register_filestation(
|
||||
)
|
||||
except _SynologyError as e:
|
||||
if e.code == 599:
|
||||
# DSM returns 599 while the async task is still initialising
|
||||
# or running (task-not-yet-available). Treat it the same as
|
||||
# finished=False and keep polling until the 60 s timeout.
|
||||
pass
|
||||
# DSM 599 = task not found. For one-shot tasks (DirSize, MD5)
|
||||
# this means either the task hasn't started yet or the result
|
||||
# window has already closed. If we've never seen the task
|
||||
# running and window_timeout has elapsed, the window is gone —
|
||||
# fail fast so the caller can retry rather than wait 60 s.
|
||||
if (
|
||||
window_timeout is not None
|
||||
and not seen_task_alive
|
||||
and elapsed >= window_timeout
|
||||
):
|
||||
return (
|
||||
False,
|
||||
"Error: Could not read task result — the operation finished"
|
||||
" before the first successful poll. Please retry.",
|
||||
)
|
||||
else:
|
||||
return False, f"Error: {e}"
|
||||
else:
|
||||
seen_task_alive = True
|
||||
if status_data.get("finished"):
|
||||
return True, status_data
|
||||
|
||||
@@ -821,7 +840,9 @@ def register_filestation(
|
||||
if not taskid:
|
||||
return "Error: DSM did not return a task ID."
|
||||
|
||||
ok, result = await _poll_task("SYNO.FileStation.DirSize", 1, taskid, initial_delay=0.0)
|
||||
ok, result = await _poll_task(
|
||||
"SYNO.FileStation.DirSize", 1, taskid, initial_delay=0.0, window_timeout=3.0
|
||||
)
|
||||
if not ok:
|
||||
return result # type: ignore[return-value]
|
||||
|
||||
@@ -882,7 +903,9 @@ def register_filestation(
|
||||
if not taskid:
|
||||
return "Error: DSM did not return a task ID."
|
||||
|
||||
ok, result = await _poll_task("SYNO.FileStation.MD5", 1, taskid, initial_delay=0.0)
|
||||
ok, result = await _poll_task(
|
||||
"SYNO.FileStation.MD5", 1, taskid, initial_delay=0.0, window_timeout=3.0
|
||||
)
|
||||
if not ok:
|
||||
return result # type: ignore[return-value]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user