Skip to content

Backend publish_interaction hangs indefinitely on Windows (write-path deadlock; reads keep serving 200) #109

Description

@smoochy

Summary

On Windows, the reflexio backend's publish_interaction endpoint (POST to http://localhost:8071/) never returns. The client blocks on the HTTP round-trip until it read-times-out; the interaction is never persisted, so nothing ever reaches the dashboard even when the backend is otherwise healthy.

Crucially, read endpoints keep answering 200 the entire time the write is hung — so the backend is up and serving, only the write path is wedged. This looks like a SQLite write-path deadlock / writer starvation.

Distinct from #107 (entrypoint allowlist) and #108 (stale backend blocking restart): here the backend is running and healthy for reads, correctly reached, correct entrypoint — the publish handler itself hangs.

Environment

Reproduction

Minimal, isolated from the hook — direct SDK call with wait_for_response=False:

import time
from reflexio.client.client import ReflexioClient

c = ReflexioClient(url_endpoint="http://localhost:8071/", timeout=65)
t = time.time()
c.publish_interaction(
    user_id="VS Code",
    interactions=[
        {"role": "user", "content": "diag ping"},
        {"role": "assistant", "content": "diag pong"},
    ],
    session_id="diag",
    wait_for_response=False,
)
print("%.1fs" % (time.time() - t))

Result:

ERR 67.08s: ReadTimeout(HTTPConnectionPool(host='localhost', port=8071):
            Read timed out. (read timeout=65))

Per the SDK docstring, wait_for_response=False should return in ~100 ms after registering a BackgroundTask. It instead hangs indefinitely (reproduced at 5 s, 30 s, 60 s client timeouts — always times out).

Evidence it's the write path specifically, not the whole backend

  • Read endpoints answer 200 continuously during the hung publish (from the dashboard's own polling in backend.log):
    POST /api/get_user_playbooks   200 OK
    POST /api/get_agent_playbooks  200 OK
    GET  /api/get_all_profiles     200 OK
    GET  /stall_state              200 OK
    
  • The POST /publish... request never produces a completion log line in backend.log (uvicorn logs on response completion → a hung handler never logs).
  • Via the Stop hook the same failure surfaces as, in ~/.claude-smart/hook.log:
    {"event":"stop","internal_skipped":false,"handler_status":"ok",
     "publish_status":"failed","publish_count":2}
    and on stderr: publish_interaction failed: HTTPConnectionPool(host='localhost', port=8071): Read timed out.
  • DB row counts stay 0 after every attempt (interactions, requests, profiles).

Correlated DB state

~/.reflexio/data/:

reflexio.db        4 KB
reflexio.db-shm   32 KB
reflexio.db-wal  ~2.6 MB   <-- large, never checkpointed

The WAL is multi-MB and never checkpoints while the dashboard polls continuously. Consistent with a long-lived reader snapshot preventing WAL checkpoint and a writer blocked on the write lock. Windows SQLite file-locking is stricter than POSIX, which may explain why this manifests here.

Additionally, once a publish has hung, backend restart itself hangs (startup DB init appears to block the same way), which compounds recovery.

Expected

publish_interaction(wait_for_response=False) returns ~200 promptly; the interaction is persisted and the WAL checkpoints; the dashboard shows the entry.

Notes / possible directions

  • Confirm whether the publish handler holds a synchronous SQLite write while the event loop keeps serving async reads (thread-pool writer blocked on the lock).
  • Check WAL checkpoint policy under continuous read polling on Windows (PRAGMA wal_autocheckpoint, busy_timeout, checkpoint-on-write).
  • A busy_timeout on the writer + a bounded publish handler timeout would at least turn the silent hang into a fast, loggable error.

Happy to run any additional probes or capture a stack dump of the backend while it's wedged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions