mirror of
https://github.com/simonw/datasette.git
synced 2026-05-31 06:07:05 +02:00
Wire Datasette.close into ASGI lifespan shutdown
AsgiLifespan now receives an on_shutdown callback that invokes Datasette.close(), so resources are released cleanly when the ASGI server delivers a lifespan.shutdown message (SIGTERM / SIGINT for uvicorn). Refs #2692 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
290f27158f
commit
d72dd35378
2 changed files with 27 additions and 1 deletions
|
|
@ -2338,10 +2338,13 @@ class Datasette:
|
|||
if not database.is_mutable:
|
||||
await database.table_counts(limit=60 * 60 * 1000)
|
||||
|
||||
async def _close_on_shutdown():
|
||||
self.close()
|
||||
|
||||
asgi = CrossOriginProtectionMiddleware(DatasetteRouter(self, routes), self)
|
||||
if self.setting("trace_debug"):
|
||||
asgi = AsgiTracer(asgi)
|
||||
asgi = AsgiLifespan(asgi)
|
||||
asgi = AsgiLifespan(asgi, on_shutdown=[_close_on_shutdown])
|
||||
asgi = AsgiRunOnFirstRequest(asgi, on_startup=[setup_db, self.invoke_startup])
|
||||
for wrapper in pm.hook.asgi_wrapper(datasette=self):
|
||||
asgi = wrapper(asgi)
|
||||
|
|
|
|||
|
|
@ -256,6 +256,29 @@ async def test_datasette_close_raises_on_use():
|
|||
await ds.get_internal_database().execute("select 1")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_asgi_lifespan_shutdown_closes_datasette():
|
||||
ds = Datasette(memory=True)
|
||||
app = ds.app()
|
||||
# Drive an ASGI lifespan: startup, then shutdown.
|
||||
messages_sent = []
|
||||
inbox = [
|
||||
{"type": "lifespan.startup"},
|
||||
{"type": "lifespan.shutdown"},
|
||||
]
|
||||
|
||||
async def receive():
|
||||
return inbox.pop(0)
|
||||
|
||||
async def send(message):
|
||||
messages_sent.append(message)
|
||||
|
||||
await app({"type": "lifespan"}, receive, send)
|
||||
assert {"type": "lifespan.startup.complete"} in messages_sent
|
||||
assert {"type": "lifespan.shutdown.complete"} in messages_sent
|
||||
assert ds._closed
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_datasette_close_continues_past_db_error():
|
||||
# If one Database raises during close(), the others still get closed.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue