Skip to content

feat(api): bound ANSWER reader by wall-clock timeout + document ask/write#196

Merged
KailasMahavarkar merged 1 commit into
mainfrom
feat/reader-timeout-and-ask-docs
May 7, 2026
Merged

feat(api): bound ANSWER reader by wall-clock timeout + document ask/write#196
KailasMahavarkar merged 1 commit into
mainfrom
feat/reader-timeout-and-ask-docs

Conversation

@KailasMahavarkar
Copy link
Copy Markdown
Contributor

Summary

  • Reader timeout (correctness fix). ANSWER's reader callable was unbounded — a hung local LLM blocked the executor thread forever. Now wrapped in a daemon-thread + worker.join(timeout=N). On timeout the result still comes back with data[\"answer\"] == \"\", data[\"error\"] describing the timeout, and a meta[\"warnings\"] entry. Threshold via GraphStore(reader_timeout_seconds=...), default 60s. Constructor rejects non-positive values.
  • README. Adds the missing docs for g.ask / g.write (introduced in feat(api): auto-fetch Bonsai GGUF + GraphStore.ask/write surface #195) — the chat-app shape: ingestor= factory, reader=, the new timeout knob, and how to drive question-shape routing through Bonsai via dry_run=True.

Trade-off

Python cannot cancel a running thread, so a genuinely stuck reader leaks one daemon thread per call. Daemons don't block process exit and a warning is logged on each leak so it's observable. Demanding cancellable readers is too much to require from callers. Net: failures become observable (was: silent hangs).

Test plan

  • Fast reader: clean answer, no error key, no warnings.
  • Slow reader (5s) with reader_timeout_seconds=0.3: returns at 0.3s with data[\"error\"] + meta[\"warnings\"]; warning logged.
  • Reader that raises: data[\"error\"] populated with the exception, no timeout reported.
  • reader_timeout_seconds=0 rejected at construction with ValueError.
  • pip install graphstore[pro] UX from feat(api): auto-fetch Bonsai GGUF + GraphStore.ask/write surface #195 still works (no regression).
  • CI green on 3.10 / 3.11 / 3.12 / 3.13.

…rite

Two follow-ups to #195:

- ANSWER's reader callable was previously unbounded - a hung local LLM
  would lock the executor thread indefinitely. Wrap the call in a daemon
  thread with `worker.join(timeout=N)`. On timeout the call returns with
  data["answer"] == "", data["error"] describing the timeout, and a
  meta["warnings"] entry; a warning is logged so the leak is visible.
  Threshold is configurable via `GraphStore(reader_timeout_seconds=...)`,
  default 60s. Constructor rejects non-positive values up-front.

  Trade-off: Python cannot cancel a running thread, so a genuinely stuck
  reader leaks one daemon per call. Acceptable - daemons don't block
  process exit, and demanding cancellable readers is too much to require
  from callers.

- README: Replaced no docs for `g.ask` / `g.write` (added in #195) with a
  small section showing the chat-app shape: ingestor= factory for NL
  writes, reader= for synthesis, the new reader_timeout_seconds knob,
  and a pointer to dry-run for question-shape routing through Bonsai.

Verified end-to-end in container: fast reader returns cleanly; slow
reader (5s) is bounded at 0.3s with proper error + warning surfaced;
exception readers are caught; reader_timeout_seconds=0 raises ValueError
at construction.
@KailasMahavarkar KailasMahavarkar merged commit c479d10 into main May 7, 2026
5 checks passed
@KailasMahavarkar KailasMahavarkar deleted the feat/reader-timeout-and-ask-docs branch May 7, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant