fix(db): upsert_node Race-Condition behoben (UNIQUE constraint)
INSERT OR IGNORE + UPDATE statt SELECT → INSERT eliminiert den UNIQUE-constraint-Fehler bei konkurrierenden async-Aufrufen. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fd9eb99b6a
commit
b431797d32
|
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## [0.08.20] - 2026-02-20
|
||||
|
||||
### Fixed
|
||||
- **`upsert_node` Race-Condition** (`UNIQUE constraint failed: nodes.node_id`):
|
||||
Statt SELECT → INSERT nutzt die Methode jetzt `INSERT OR IGNORE` + `UPDATE`,
|
||||
wodurch konkurrierende Aufrufe keinen Constraint-Fehler mehr auslösen.
|
||||
|
||||
## [0.08.19] - 2026-02-20
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version: "0.08.19"
|
||||
version: "0.08.20"
|
||||
|
||||
bot:
|
||||
name: "MeshDD-Bot"
|
||||
|
|
|
|||
|
|
@ -129,29 +129,19 @@ class Database:
|
|||
|
||||
async def upsert_node(self, node_id: str, **kwargs) -> dict:
|
||||
now = time.time()
|
||||
existing = await self.get_node(node_id)
|
||||
|
||||
if existing:
|
||||
updates = {k: v for k, v in kwargs.items() if v is not None}
|
||||
if not updates:
|
||||
return dict(existing)
|
||||
updates["last_seen"] = now
|
||||
set_clause = ", ".join(f"{k} = ?" for k in updates)
|
||||
values = list(updates.values()) + [node_id]
|
||||
await self.db.execute(
|
||||
f"UPDATE nodes SET {set_clause} WHERE node_id = ?", values
|
||||
)
|
||||
else:
|
||||
kwargs["node_id"] = node_id
|
||||
kwargs.setdefault("first_seen", now)
|
||||
kwargs["last_seen"] = now
|
||||
cols = ", ".join(kwargs.keys())
|
||||
placeholders = ", ".join("?" for _ in kwargs)
|
||||
await self.db.execute(
|
||||
f"INSERT INTO nodes ({cols}) VALUES ({placeholders})",
|
||||
list(kwargs.values()),
|
||||
)
|
||||
|
||||
# Row anlegen falls nicht vorhanden (first_seen nur beim ersten Mal gesetzt)
|
||||
await self.db.execute(
|
||||
"INSERT OR IGNORE INTO nodes (node_id, first_seen, last_seen) VALUES (?, ?, ?)",
|
||||
(node_id, now, now),
|
||||
)
|
||||
# Nicht-None-Felder + last_seen immer aktualisieren
|
||||
updates = {k: v for k, v in kwargs.items() if v is not None}
|
||||
updates["last_seen"] = now
|
||||
set_clause = ", ".join(f"{k} = ?" for k in updates)
|
||||
values = list(updates.values()) + [node_id]
|
||||
await self.db.execute(
|
||||
f"UPDATE nodes SET {set_clause} WHERE node_id = ?", values
|
||||
)
|
||||
await self.db.commit()
|
||||
return dict(await self.get_node(node_id))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue