|
1 | 1 | import os |
2 | 2 | import json |
3 | 3 | import logging |
4 | | -from contextlib import asynccontextmanager, contextmanager |
| 4 | +from contextlib import asynccontextmanager, contextmanager, closing |
5 | 5 | from typing import Any, Optional |
6 | 6 |
|
7 | 7 | from open_webui.internal.wrappers import register_connection |
@@ -108,6 +108,22 @@ def _make_async_url(url: str) -> str: |
108 | 108 | # Alembic, peewee migration, health checks) |
109 | 109 | # ============================================================ |
110 | 110 |
|
| 111 | +# Shared SQLite connection handler, used by both sync and async engines |
| 112 | +def _sqlite_on_connect(dbapi_connection, connection_record): |
| 113 | + with closing(dbapi_connection.cursor()) as cursor: |
| 114 | + if DATABASE_ENABLE_SQLITE_WAL: |
| 115 | + cursor.execute('PRAGMA journal_mode=WAL') |
| 116 | + # synchronous=NORMAL is safe with WAL: durable on app crash, may roll back |
| 117 | + # last transactions on OS crash or power loss; acceptable for most web apps. |
| 118 | + cursor.execute('PRAGMA synchronous=NORMAL') |
| 119 | + cursor.execute('PRAGMA journal_size_limit=67108864') # Cap WAL file at 64 MB |
| 120 | + cursor.execute('PRAGMA cache_size=-32768') # 32 MB page cache, per connection |
| 121 | + cursor.execute('PRAGMA temp_store=MEMORY') |
| 122 | + cursor.execute('PRAGMA busy_timeout=5000') # Retry up to 5 s on lock contention |
| 123 | + else: |
| 124 | + cursor.execute('PRAGMA journal_mode=DELETE') |
| 125 | + |
| 126 | + |
111 | 127 | # Handle SQLCipher URLs |
112 | 128 | if SQLALCHEMY_DATABASE_URL.startswith('sqlite+sqlcipher://'): |
113 | 129 | database_password = os.environ.get('DATABASE_PASSWORD') |
@@ -154,16 +170,7 @@ def create_sqlcipher_connection(): |
154 | 170 |
|
155 | 171 | elif 'sqlite' in SQLALCHEMY_DATABASE_URL: |
156 | 172 | engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False}) |
157 | | - |
158 | | - def on_connect(dbapi_connection, connection_record): |
159 | | - cursor = dbapi_connection.cursor() |
160 | | - if DATABASE_ENABLE_SQLITE_WAL: |
161 | | - cursor.execute('PRAGMA journal_mode=WAL') |
162 | | - else: |
163 | | - cursor.execute('PRAGMA journal_mode=DELETE') |
164 | | - cursor.close() |
165 | | - |
166 | | - event.listen(engine, 'connect', on_connect) |
| 173 | + event.listen(engine, 'connect', _sqlite_on_connect) |
167 | 174 | else: |
168 | 175 | if isinstance(DATABASE_POOL_SIZE, int): |
169 | 176 | if DATABASE_POOL_SIZE > 0: |
@@ -212,14 +219,7 @@ def get_session(): |
212 | 219 | ASYNC_SQLALCHEMY_DATABASE_URL, |
213 | 220 | connect_args={'check_same_thread': False}, |
214 | 221 | ) |
215 | | - |
216 | | - if DATABASE_ENABLE_SQLITE_WAL: |
217 | | - |
218 | | - @event.listens_for(async_engine.sync_engine, 'connect') |
219 | | - def _set_sqlite_wal(dbapi_connection, connection_record): |
220 | | - cursor = dbapi_connection.cursor() |
221 | | - cursor.execute('PRAGMA journal_mode=WAL') |
222 | | - cursor.close() |
| 222 | + event.listen(async_engine.sync_engine, 'connect', _sqlite_on_connect) |
223 | 223 | else: |
224 | 224 | if isinstance(DATABASE_POOL_SIZE, int): |
225 | 225 | if DATABASE_POOL_SIZE > 0: |
|
0 commit comments