From acbc5150cfa61991edb2081aefaf3c6b939f9d70 Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Tue, 17 Mar 2026 12:56:34 +0800 Subject: [PATCH] fix: SQLite 'database is locked' by adding busy timeout (#6474) The async engine is created without a busy timeout, so concurrent writes (agent responses, metrics, session updates) fail instantly with 'database is locked' instead of waiting for the lock. Add connect_args={'timeout': 30} for SQLite engines so the driver waits up to 30 seconds for the write lock. Combined with the existing WAL journal mode, this handles the typical concurrent write bursts from agent + metrics + session operations. Fixes #6443 --- astrbot/core/db/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/astrbot/core/db/__init__.py b/astrbot/core/db/__init__.py index 608ecc710..a18c127eb 100644 --- a/astrbot/core/db/__init__.py +++ b/astrbot/core/db/__init__.py @@ -33,10 +33,18 @@ class BaseDatabase(abc.ABC): DATABASE_URL = "" def __init__(self) -> None: + # SQLite only supports a single writer at a time. Without a busy + # timeout the driver raises "database is locked" instantly when a + # second write is attempted. Setting timeout=30 tells SQLite to + # wait up to 30 s for the lock, which is enough to ride out brief + # write bursts from concurrent agent/metrics/session operations. + is_sqlite = "sqlite" in self.DATABASE_URL + connect_args = {"timeout": 30} if is_sqlite else {} self.engine = create_async_engine( self.DATABASE_URL, echo=False, future=True, + connect_args=connect_args, ) self.AsyncSessionLocal = async_sessionmaker( self.engine,