mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-14 11:10:47 +08:00
fix: harden assistant SQLite/PostgreSQL dual-backend (singleton, timeouts, warnings)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
1490bd5f24
commit
1caf96e694
8 changed files with 129 additions and 15 deletions
|
|
@ -2,13 +2,20 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
from svc.config.database import assistant_db_backend, assistant_postgres_dsn
|
||||
from svc.config.database import (
|
||||
assistant_db_backend,
|
||||
assistant_postgres_dsn,
|
||||
assistant_sqlalchemy_url,
|
||||
)
|
||||
from svc.persistence.assistant_store_protocol import AssistantStoreProtocol
|
||||
|
||||
_singleton: AssistantStoreProtocol | None = None
|
||||
_singleton_key: str | None = None
|
||||
_lock = threading.Lock()
|
||||
|
||||
|
||||
def reset_assistant_store_singleton() -> None:
|
||||
|
|
@ -29,6 +36,12 @@ def get_assistant_store() -> AssistantStoreProtocol:
|
|||
does not re-run PostgreSQL bootstrap / orphan pruning on every HTTP or WS call (which could race
|
||||
with in-flight writes and make messages disappear after tool rounds).
|
||||
|
||||
The cache key for PostgreSQL uses a **hash of the SQLAlchemy URL** (not the raw DSN string) so logs
|
||||
and debug dumps are less likely to embed credentials.
|
||||
|
||||
When the effective key changes (e.g. tests switch ``AIA_ASSISTANT_DB_PATH`` or DSN), the SQLAlchemy
|
||||
engine cache is cleared so pooled connections are not reused for the wrong database.
|
||||
|
||||
Tests should keep constructing ``SqliteStore(path)`` with an explicit file path; production code
|
||||
should prefer this factory for ``db_path()``-backed instances.
|
||||
|
||||
|
|
@ -40,18 +53,27 @@ def get_assistant_store() -> AssistantStoreProtocol:
|
|||
from svc.persistence.sqlite_store import SqliteStore
|
||||
|
||||
if assistant_db_backend() == "postgresql":
|
||||
key = f"postgresql::{assistant_postgres_dsn()}"
|
||||
key = f"postgresql::{hashlib.sha256(assistant_sqlalchemy_url().encode()).hexdigest()}"
|
||||
else:
|
||||
key = f"sqlite::{Path(db_path()).resolve()}"
|
||||
|
||||
if _singleton is not None and _singleton_key == key:
|
||||
inst = _singleton
|
||||
if inst is not None and _singleton_key == key:
|
||||
return inst
|
||||
|
||||
with _lock:
|
||||
if _singleton is not None and _singleton_key == key:
|
||||
return _singleton
|
||||
if _singleton_key is not None and _singleton_key != key:
|
||||
from svc.persistence.db.engine import clear_assistant_engine_cache
|
||||
|
||||
clear_assistant_engine_cache()
|
||||
if assistant_db_backend() == "postgresql":
|
||||
_singleton = SqliteStore(None, postgres_url=assistant_postgres_dsn())
|
||||
else:
|
||||
_singleton = SqliteStore(db_path())
|
||||
_singleton_key = key
|
||||
return _singleton
|
||||
if assistant_db_backend() == "postgresql":
|
||||
_singleton = SqliteStore(None, postgres_url=assistant_postgres_dsn())
|
||||
else:
|
||||
_singleton = SqliteStore(db_path())
|
||||
_singleton_key = key
|
||||
return _singleton
|
||||
|
||||
|
||||
__all__ = ["get_assistant_store", "reset_assistant_store_singleton"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue