notebookvb
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -31,6 +31,72 @@ def get_medicus_connection():
|
||||
return fdb.connect(dsn=dsn, user="SYSDBA", password="masterkey", charset="win1250")
|
||||
|
||||
|
||||
class ReconnectingConnection:
|
||||
"""Obal nad fdb.Connection, který se sám znovu připojí, když spojení umře.
|
||||
|
||||
Dlouho běžící procesy (např. MCP server) drží jedno spojení od startu.
|
||||
To se rozpadne, když:
|
||||
* se notebook uspí/hibernuje (TCP socket odumře), nebo
|
||||
* na serveru proběhne denní gbak restore (Firebird zabije stará spojení).
|
||||
Výsledkem je `SQLCODE -902 Error writing data to the connection`.
|
||||
|
||||
Tato třída ověří před každým použitím, že spojení žije, a když ne,
|
||||
tiše ho znovu naváže. Volající kód používá .cursor()/.commit() beze změny.
|
||||
"""
|
||||
|
||||
def __init__(self, connect_fn=get_medicus_connection):
|
||||
self._connect = connect_fn
|
||||
self._conn = None
|
||||
|
||||
def _alive(self):
|
||||
if self._conn is None:
|
||||
return False
|
||||
try:
|
||||
cur = self._conn.cursor()
|
||||
cur.execute("SELECT 1 FROM RDB$DATABASE")
|
||||
cur.fetchone()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _ensure(self):
|
||||
if not self._alive():
|
||||
if self._conn is not None:
|
||||
try:
|
||||
self._conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
self._conn = None
|
||||
self._conn = self._connect()
|
||||
return self._conn
|
||||
|
||||
def cursor(self):
|
||||
return self._ensure().cursor()
|
||||
|
||||
def commit(self):
|
||||
return self._ensure().commit()
|
||||
|
||||
def rollback(self):
|
||||
if self._conn is not None:
|
||||
return self._conn.rollback()
|
||||
|
||||
def close(self):
|
||||
if self._conn is not None:
|
||||
try:
|
||||
self._conn.close()
|
||||
finally:
|
||||
self._conn = None
|
||||
|
||||
def __getattr__(self, name):
|
||||
# ostatní atributy/metody proxy na živé spojení
|
||||
return getattr(self._ensure(), name)
|
||||
|
||||
|
||||
def get_medicus_connection_reconnecting():
|
||||
"""Vrátí spojení s automatickým reconnectem (vhodné pro dlouho běžící procesy)."""
|
||||
return ReconnectingConnection(get_medicus_connection)
|
||||
|
||||
|
||||
def get_medicus_db():
|
||||
"""Vrátí MedicusDB instanci s připojením podle názvu počítače."""
|
||||
conn = get_medicus_connection()
|
||||
|
||||
+8
-5
@@ -12,20 +12,23 @@ from typing import Optional
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from Knihovny.medicus_db import get_medicus_connection
|
||||
from Knihovny.medicus_db import get_medicus_connection_reconnecting
|
||||
|
||||
# Všechny logy MUSÍ jít na stderr — stdout je rezervován pro JSON-RPC
|
||||
def log(msg: str):
|
||||
print(msg, file=sys.stderr, flush=True)
|
||||
|
||||
|
||||
# Připojení k Firebirdu
|
||||
# Připojení k Firebirdu — lazy + auto-reconnect.
|
||||
# Spojení se naváže až při prvním dotazu a samo se obnoví, když umře
|
||||
# (uspání notebooku, denní gbak restore na serveru). Proto nepadáme při startu,
|
||||
# i kdyby DB zrovna nebyla dostupná.
|
||||
conn = get_medicus_connection_reconnecting()
|
||||
try:
|
||||
conn = get_medicus_connection()
|
||||
conn.cursor().execute("SELECT 1 FROM RDB$DATABASE")
|
||||
log("✓ Připojeno k Firebirdu (Medicus)")
|
||||
except Exception as e:
|
||||
log(f"✗ Chyba připojení k Firebirdu: {e}")
|
||||
sys.exit(1)
|
||||
log(f"⚠ Firebird zatím nedostupný, zkusím se připojit při prvním dotazu: {e}")
|
||||
|
||||
|
||||
def rows_to_json(rows, description):
|
||||
|
||||
Reference in New Issue
Block a user