From 91e0c2ee62387904c06136a5be8280b773c2f5cc Mon Sep 17 00:00:00 2001 From: mackaby Date: Thu, 5 Mar 2026 09:16:30 +0100 Subject: [PATCH] feat(db): add backend shutdown hook for graceful runtime shutdown Add Database::shutdown() with a default no-op implementation for backward compatibility. Implement libSQL shutdown via flush_replicator(), treating SyncNotSupported as non-fatal. Implement Postgres shutdown by closing the pool. --- src/db/libsql/mod.rs | 12 ++++++++++++ src/db/mod.rs | 7 +++++++ src/db/postgres.rs | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/src/db/libsql/mod.rs b/src/db/libsql/mod.rs index a5c48f3f..d089252f 100644 --- a/src/db/libsql/mod.rs +++ b/src/db/libsql/mod.rs @@ -326,6 +326,18 @@ impl Database for LibSqlBackend { libsql_migrations::run_incremental(&conn).await?; Ok(()) } + + async fn shutdown(&self) -> Result<(), DatabaseError> { + match self.db.flush_replicator().await { + Ok(Some(frame_no)) => { + tracing::debug!("libSQL replicator flushed at frame {}", frame_no); + Ok(()) + } + Ok(None) => Ok(()), + Err(libsql::Error::SyncNotSupported(_)) => Ok(()), + Err(error) => Err(DatabaseError::from(error)), + } + } } // ==================== Row conversion helpers ==================== diff --git a/src/db/mod.rs b/src/db/mod.rs index 4afd1db8..54640fe4 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -523,6 +523,13 @@ pub trait Database: { /// Run schema migrations for this backend. async fn run_migrations(&self) -> Result<(), DatabaseError>; + + /// Shutdown hook for backend-specific drain/flush behavior. + /// + /// Default implementation is a no-op so existing backends remain compatible. + async fn shutdown(&self) -> Result<(), DatabaseError> { + Ok(()) + } } #[cfg(test)] diff --git a/src/db/postgres.rs b/src/db/postgres.rs index 2cf6a65a..12a6a795 100644 --- a/src/db/postgres.rs +++ b/src/db/postgres.rs @@ -61,6 +61,11 @@ impl Database for PgBackend { async fn run_migrations(&self) -> Result<(), DatabaseError> { self.store.run_migrations().await } + + async fn shutdown(&self) -> Result<(), DatabaseError> { + self.store.pool().close(); + Ok(()) + } } // ==================== ConversationStore ====================