Context manager for database connections. Ensures thread-safe access and automatic cleanup. Usage: with db.get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM hosts")
(self)
| 127 | |
| 128 | @contextmanager |
| 129 | def get_connection(self): |
| 130 | """ |
| 131 | Context manager for database connections. |
| 132 | Ensures thread-safe access and automatic cleanup. |
| 133 | |
| 134 | Usage: |
| 135 | with db.get_connection() as conn: |
| 136 | cursor = conn.cursor() |
| 137 | cursor.execute("SELECT * FROM hosts") |
| 138 | """ |
| 139 | conn = None |
| 140 | try: |
| 141 | with self.lock: |
| 142 | # timeout: wait up to 30s for a lock instead of erroring instantly. |
| 143 | conn = sqlite3.connect(self.db_path, check_same_thread=False, |
| 144 | timeout=30) |
| 145 | conn.row_factory = sqlite3.Row # Enable dict-like access |
| 146 | # WAL lets readers (the dashboard) run concurrently with the |
| 147 | # writer (the scanner) instead of blocking — this is what fixes |
| 148 | # the recurring "database is locked" on /api/dashboard/stats. |
| 149 | # WAL is persisted in the DB header, so this converts the file |
| 150 | # once and stays; setting it per-connection is a cheap no-op. |
| 151 | conn.execute("PRAGMA journal_mode=WAL") |
| 152 | conn.execute("PRAGMA busy_timeout=30000") |
| 153 | conn.execute("PRAGMA synchronous=NORMAL") # safe under WAL, less fsync |
| 154 | conn.execute("PRAGMA foreign_keys = ON") # Enable foreign keys |
| 155 | yield conn |
| 156 | conn.commit() |
| 157 | except Exception as e: |
no test coverage detected