Files
openswarm/backend/apps/service/buffer.py
Arnav NavalandCursor 9100e91652 [arnav] clean up unused imports and dead local variables
Auto-fixed 52 ruff F401 findings (unused imports) across 22 files
in backend/ and backend/tests/. Manually resolved 8 F841 unused
locals that ruff flagged as unsafe-fix:

- agent_manager.resume_session: drop dead hours_since_closed block.
- main.py mcp-meta + outputs-meta activate handlers: drop dead
  reason = body.get("reason") binding (server ignores the field).
- dashboards.seed_demo, tools_lib.m365_device_login: keep _load(...)
  call for its 404 side-effect, drop unused binding, add intent
  comment.
- outputs.auto_run_output: keep `import anthropic` as availability
  probe, mark with `# noqa: F401` and explanation.
- dead_code_scan._extract_ws_event_branches: drop vestigial
  ws_handler_lines set (never written or read).
- test_browser_agent_unit.test_hash_tool_call_falls_back_to_repr:
  drop the unused _Boom class+instance (the actual self-referential
  bait is bad_input/bad_result; _Boom was never passed to the
  function under test).

Result: 1184/1184 backend tests pass (1 deselected: pre-existing
sandbox-only git test). ruff --select F401,F811,F841 backend/ now
clean (was 60 findings).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 18:30:34 -05:00

139 lines
5.0 KiB
Python

"""Bounded SQLite spool for offline operational submissions.
When the desktop is offline (laptop closed, no internet, cloud unreachable),
the service-sync layer can't reach `api.openswarm.com`. Rather than drop
data on the floor, we spool submissions to a small SQLite file and replay
them on the next online tick. The spool is bounded — when full, the oldest
entries are dropped — so it can never balloon to a problem.
Single file, single table, single thread guarded by a sqlite3 connection's
implicit lock. No concurrency model beyond "don't write from two processes
at once."
"""
from __future__ import annotations
import json
import logging
import os
import sqlite3
import threading
from contextlib import contextmanager
from typing import Iterator
logger = logging.getLogger(__name__)
# Cap the spool at 50 MB on disk. SQLite's overhead means the actual ceiling
# on retained payloads is somewhat smaller, which is fine — this is a
# best-effort cushion, not a guaranteed retention window.
_MAX_BYTES = 50 * 1024 * 1024
# Trim 25% when we cross the cap so we don't trim on every insert.
_TRIM_TARGET_FRACTION = 0.75
_lock = threading.Lock()
@contextmanager
def _conn(spool_path: str) -> Iterator[sqlite3.Connection]:
"""Open a connection that auto-commits and ensures the table exists.
Caller holds `_lock` for the duration of the context."""
os.makedirs(os.path.dirname(spool_path), exist_ok=True)
c = sqlite3.connect(spool_path, isolation_level=None, timeout=5.0)
try:
c.execute(
"CREATE TABLE IF NOT EXISTS spool ("
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
" kind TEXT NOT NULL,"
" payload TEXT NOT NULL,"
" created_at REAL NOT NULL"
")"
)
yield c
finally:
c.close()
def enqueue(spool_path: str, kind: str, payload: dict, *, now: float) -> None:
"""Append a submission to the spool. Drops the oldest if the spool is
over the byte cap."""
body = json.dumps(payload, separators=(",", ":"), default=str)
with _lock, _conn(spool_path) as c:
c.execute(
"INSERT INTO spool (kind, payload, created_at) VALUES (?, ?, ?)",
(kind, body, now),
)
# Cheap size check — only run trim when stat says we're over.
try:
size = os.path.getsize(spool_path)
except OSError:
size = 0
if size > _MAX_BYTES:
target = int(_MAX_BYTES * _TRIM_TARGET_FRACTION)
# Delete oldest rows until we're back under target. Use a
# reasonable batch size so we don't block forever.
for _ in range(64):
row = c.execute("SELECT id FROM spool ORDER BY id ASC LIMIT 1").fetchone()
if not row:
break
c.execute("DELETE FROM spool WHERE id = ?", (row[0],))
try:
new_size = os.path.getsize(spool_path)
except OSError:
new_size = 0
if new_size <= target:
break
# VACUUM is expensive; only run if we still appear oversized after
# trimming, otherwise free pages get reused on next insert.
try:
if os.path.getsize(spool_path) > _MAX_BYTES:
c.execute("VACUUM")
except (OSError, sqlite3.DatabaseError):
pass
def drain(spool_path: str, batch_size: int = 50) -> list[tuple[int, str, dict]]:
"""Read up to `batch_size` oldest entries. Returns (id, kind, payload)
triples; caller is responsible for calling `acknowledge(ids)` once the
cloud accepts them."""
if not os.path.exists(spool_path):
return []
with _lock, _conn(spool_path) as c:
rows = c.execute(
"SELECT id, kind, payload FROM spool ORDER BY id ASC LIMIT ?",
(batch_size,),
).fetchall()
out: list[tuple[int, str, dict]] = []
for rid, kind, body in rows:
try:
out.append((rid, kind, json.loads(body)))
except json.JSONDecodeError:
# Corrupt row — discard so it doesn't block draining behind it.
with _lock, _conn(spool_path) as c:
c.execute("DELETE FROM spool WHERE id = ?", (rid,))
logger.warning("Dropped corrupt spool row id=%s", rid)
return out
def acknowledge(spool_path: str, ids: list[int]) -> None:
"""Remove rows the cloud has accepted."""
if not ids:
return
with _lock, _conn(spool_path) as c:
c.executemany("DELETE FROM spool WHERE id = ?", [(i,) for i in ids])
def count(spool_path: str) -> int:
"""Return the number of pending entries. Used for tests + debug UI."""
if not os.path.exists(spool_path):
return 0
with _lock, _conn(spool_path) as c:
row = c.execute("SELECT COUNT(*) FROM spool").fetchone()
return int(row[0]) if row else 0
def clear(spool_path: str) -> None:
"""Delete all pending entries. Tests + manual reset only."""
with _lock, _conn(spool_path) as c:
c.execute("DELETE FROM spool")