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")
|
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():
|
def get_medicus_db():
|
||||||
"""Vrátí MedicusDB instanci s připojením podle názvu počítače."""
|
"""Vrátí MedicusDB instanci s připojením podle názvu počítače."""
|
||||||
conn = get_medicus_connection()
|
conn = get_medicus_connection()
|
||||||
|
|||||||
+8
-5
@@ -12,20 +12,23 @@ from typing import Optional
|
|||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
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
|
# Všechny logy MUSÍ jít na stderr — stdout je rezervován pro JSON-RPC
|
||||||
def log(msg: str):
|
def log(msg: str):
|
||||||
print(msg, file=sys.stderr, flush=True)
|
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:
|
try:
|
||||||
conn = get_medicus_connection()
|
conn.cursor().execute("SELECT 1 FROM RDB$DATABASE")
|
||||||
log("✓ Připojeno k Firebirdu (Medicus)")
|
log("✓ Připojeno k Firebirdu (Medicus)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f"✗ Chyba připojení k Firebirdu: {e}")
|
log(f"⚠ Firebird zatím nedostupný, zkusím se připojit při prvním dotazu: {e}")
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def rows_to_json(rows, description):
|
def rows_to_json(rows, description):
|
||||||
|
|||||||
Reference in New Issue
Block a user