From 1cfde06de952170e2541d9a8e730211ab764eb25 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Tue, 10 Feb 2026 22:28:38 +0000 Subject: [PATCH] Refactor DB lifecycle functions init and cleanup to separate db.lifecycle module. --- paskia/db/__init__.py | 3 +-- paskia/db/background.py | 9 +++++---- paskia/db/lifecycle.py | 39 +++++++++++++++++++++++++++++++++++++++ paskia/db/operations.py | 35 ----------------------------------- 4 files changed, 45 insertions(+), 41 deletions(-) create mode 100644 paskia/db/lifecycle.py diff --git a/paskia/db/__init__.py b/paskia/db/__init__.py index 1f7ac5c..0c5b40b 100644 --- a/paskia/db/__init__.py +++ b/paskia/db/__init__.py @@ -27,10 +27,10 @@ from paskia.db.background import ( stop_cleanup, ) from paskia.db.bootstrap import bootstrap +from paskia.db.lifecycle import cleanup_expired, init from paskia.db.operations import ( add_permission_to_org, add_permission_to_role, - cleanup_expired, create_credential, create_credential_session, create_org, @@ -52,7 +52,6 @@ from paskia.db.operations import ( get_reset_token, get_user_credential_ids, get_user_organization, - init, login, remove_permission_from_org, remove_permission_from_role, diff --git a/paskia/db/background.py b/paskia/db/background.py index debb283..e4f3a86 100644 --- a/paskia/db/background.py +++ b/paskia/db/background.py @@ -8,7 +8,8 @@ import asyncio import logging from datetime import UTC, datetime -from paskia.db.operations import _store, cleanup_expired +import paskia.db.operations as _ops +from paskia.db.lifecycle import cleanup_expired FLUSH_INTERVAL = 0.1 # Flush to disk CLEANUP_INTERVAL = 1 # Expired item cleanup @@ -20,11 +21,11 @@ _background_task: asyncio.Task | None = None async def flush() -> None: """Write all pending database changes to disk.""" - - if _store is None: + store = _ops._store + if store is None: _logger.warning("flush() called but _store is None") return - await _store.flush() + await store.flush() async def _background_loop(): diff --git a/paskia/db/lifecycle.py b/paskia/db/lifecycle.py new file mode 100644 index 0000000..c67bb93 --- /dev/null +++ b/paskia/db/lifecycle.py @@ -0,0 +1,39 @@ +""" +Database lifecycle: initialization and maintenance. +""" + +import logging +import os +from datetime import UTC, datetime + +import paskia.db.operations as _ops + +_logger = logging.getLogger(__name__) + + +async def init(rp_id: str = "localhost", *args, **kwargs): + """Load database from JSONL file.""" + if _ops._initialized: + _logger.debug("Database already initialized, skipping reload") + return + default_path = f"{rp_id}.paskiadb" + db_path = os.environ.get("PASKIA_DB", default_path) + await _ops._store.load(db_path, rp_id=rp_id) + _ops._db = _ops._store.db + _ops._initialized = True + + +def cleanup_expired() -> int: + """Remove expired sessions and reset tokens. Returns count removed.""" + now = datetime.now(UTC) + count = 0 + with _ops._db.transaction("expiry"): + expired_sessions = [k for k, s in _ops._db.sessions.items() if s.expiry < now] + for k in expired_sessions: + del _ops._db.sessions[k] + count += 1 + expired_tokens = [k for k, t in _ops._db.reset_tokens.items() if t.expiry < now] + for k in expired_tokens: + del _ops._db.reset_tokens[k] + count += 1 + return count diff --git a/paskia/db/operations.py b/paskia/db/operations.py index 67263ce..a571db1 100644 --- a/paskia/db/operations.py +++ b/paskia/db/operations.py @@ -8,7 +8,6 @@ Write operations: Functions that validate and commit, or raise ValueError. import hashlib import logging -import os from datetime import UTC, datetime, timedelta from uuid import UUID @@ -41,19 +40,6 @@ _db._store = _store _initialized = False -async def init(rp_id: str = "localhost", *args, **kwargs): - """Load database from JSONL file.""" - global _db, _initialized - if _initialized: - _logger.debug("Database already initialized, skipping reload") - return - default_path = f"{rp_id}.paskiadb" - db_path = os.environ.get("PASKIA_DB", default_path) - await _store.load(db_path, rp_id=rp_id) - _db = _store.db - _initialized = True - - # ------------------------------------------------------------------------- # Read/lookup functions # ------------------------------------------------------------------------- @@ -555,27 +541,6 @@ def delete_reset_token(key: bytes, *, ctx: SessionContext | None = None) -> None _db.reset_tokens[key].delete() -# ------------------------------------------------------------------------- -# Cleanup (called by background task) -# ------------------------------------------------------------------------- - - -def cleanup_expired() -> int: - """Remove expired sessions and reset tokens. Returns count removed.""" - now = datetime.now(UTC) - count = 0 - with _db.transaction("expiry"): - expired_sessions = [k for k, s in _db.sessions.items() if s.expiry < now] - for k in expired_sessions: - del _db.sessions[k] - count += 1 - expired_tokens = [k for k, t in _db.reset_tokens.items() if t.expiry < now] - for k in expired_tokens: - del _db.reset_tokens[k] - count += 1 - return count - - # ------------------------------------------------------------------------- # Composite operations (used by app code) # -------------------------------------------------------------------------