mirror of
https://github.com/simonw/datasette.git
synced 2026-09-11 11:04:07 +02:00
Add a default execution time limit to writes
This commit is contained in:
parent
9d3d741620
commit
ac2a9a43a5
3 changed files with 21 additions and 4 deletions
|
|
@ -247,17 +247,29 @@ class Database:
|
|||
return_all=False,
|
||||
returning_limit=EXECUTE_WRITE_RETURNING_LIMIT,
|
||||
transaction=True,
|
||||
time_limit_ms=2000,
|
||||
):
|
||||
self._check_not_closed()
|
||||
if returning_limit < 0:
|
||||
raise ValueError("returning_limit must be >= 0")
|
||||
|
||||
def _inner(conn):
|
||||
def execute_sql(conn):
|
||||
cursor = conn.execute(sql, params or [])
|
||||
return ExecuteWriteResult.from_cursor(
|
||||
cursor, return_all=return_all, returning_limit=returning_limit
|
||||
)
|
||||
|
||||
def _inner(conn):
|
||||
try:
|
||||
if time_limit_ms is None:
|
||||
return execute_sql(conn)
|
||||
with sqlite_timelimit(conn, time_limit_ms):
|
||||
return execute_sql(conn)
|
||||
except (sqlite3.OperationalError, sqlite3.DatabaseError) as e:
|
||||
if e.args == ("interrupted",):
|
||||
raise QueryInterrupted(e, sql, params)
|
||||
raise
|
||||
|
||||
with trace("sql", database=self.name, sql=sql.strip(), params=params):
|
||||
results = await self.execute_write_fn(
|
||||
_inner, block=block, request=request, transaction=transaction
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import re
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from datasette.database import QueryInterrupted
|
||||
from datasette.resources import DatabaseResource
|
||||
from datasette.utils import UNSTABLE_API_MESSAGE, sqlite3
|
||||
from datasette.utils.asgi import Response
|
||||
|
|
@ -384,7 +385,7 @@ class ExecuteWriteView(BaseView):
|
|||
try:
|
||||
execute_write_kwargs = {"request": request}
|
||||
cursor = await db.execute_write(sql, params, **execute_write_kwargs)
|
||||
except sqlite3.DatabaseError as ex:
|
||||
except (QueryInterrupted, sqlite3.DatabaseError) as ex:
|
||||
message = str(ex)
|
||||
if wants_json:
|
||||
return _block_framing(Response.error([message], 400))
|
||||
|
|
|
|||
|
|
@ -2023,8 +2023,8 @@ Example usage:
|
|||
|
||||
.. _database_execute_write:
|
||||
|
||||
await db.execute_write(sql, params=None, block=True, request=None, return_all=False, returning_limit=10, transaction=True)
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
await db.execute_write(sql, params=None, block=True, request=None, return_all=False, returning_limit=10, transaction=True, time_limit_ms=2000)
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
SQLite only allows one database connection to write at a time. Datasette handles this for you by maintaining a queue of writes to be executed against a given database. Plugins can submit write operations to this queue and they will be executed in the order in which they are received.
|
||||
|
||||
|
|
@ -2063,6 +2063,10 @@ Each call to ``execute_write()`` will be executed inside a transaction. Pass
|
|||
``transaction=False`` for statements such as ``VACUUM`` that cannot run inside
|
||||
a transaction.
|
||||
|
||||
Write statements have a default time limit of 2,000ms. Pass a different value
|
||||
using ``time_limit_ms=`` or use ``time_limit_ms=None`` to allow the statement to
|
||||
run without a time limit.
|
||||
|
||||
.. _database_execute_write_script:
|
||||
|
||||
await db.execute_write_script(sql, block=True)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue