DB background worker cleanup, avoid issue with double cleanup. Faster write to disk.
This commit is contained in:
+6
-32
@@ -8,42 +8,16 @@ import asyncio
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from paskia.db.operations import _db, _store
|
||||
from paskia.db.operations import _store, cleanup_expired
|
||||
|
||||
# Flush changes to disk every N seconds
|
||||
FLUSH_INTERVAL = 1
|
||||
# Cleanup expired items every N seconds (cheap when nothing to remove)
|
||||
CLEANUP_INTERVAL = 1
|
||||
FLUSH_INTERVAL = 0.1 # Flush to disk
|
||||
CLEANUP_INTERVAL = 1 # Expired item cleanup
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_background_task: asyncio.Task | None = None
|
||||
|
||||
|
||||
def cleanup() -> None:
|
||||
"""Remove expired sessions and reset tokens from the database."""
|
||||
|
||||
if _db is None:
|
||||
return
|
||||
|
||||
with _db.transaction("expiry"):
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
||||
# Clean expired sessions
|
||||
to_delete_sessions = [
|
||||
k for k, s in _db.sessions.items() if s.expiry < current_time
|
||||
]
|
||||
for k in to_delete_sessions:
|
||||
del _db.sessions[k]
|
||||
|
||||
# Clean expired reset tokens
|
||||
to_delete_tokens = [
|
||||
k for k, t in _db.reset_tokens.items() if t.expiry < current_time
|
||||
]
|
||||
for k in to_delete_tokens:
|
||||
del _db.reset_tokens[k]
|
||||
|
||||
|
||||
async def flush() -> None:
|
||||
"""Write all pending database changes to disk."""
|
||||
|
||||
@@ -56,7 +30,7 @@ async def flush() -> None:
|
||||
async def _background_loop():
|
||||
"""Background task that periodically flushes changes and cleans up."""
|
||||
# Run cleanup immediately on startup to clear old expired items
|
||||
cleanup()
|
||||
cleanup_expired()
|
||||
await flush()
|
||||
|
||||
last_cleanup = datetime.now(timezone.utc)
|
||||
@@ -67,10 +41,10 @@ async def _background_loop():
|
||||
# Flush pending changes to disk
|
||||
await flush()
|
||||
|
||||
# Run cleanup less frequently
|
||||
# Run cleanup periodically
|
||||
now = datetime.now(timezone.utc)
|
||||
if (now - last_cleanup).total_seconds() >= CLEANUP_INTERVAL:
|
||||
cleanup()
|
||||
cleanup_expired()
|
||||
await flush() # Flush cleanup changes
|
||||
last_cleanup = now
|
||||
except asyncio.CancelledError:
|
||||
|
||||
@@ -675,7 +675,7 @@ def cleanup_expired() -> int:
|
||||
"""Remove expired sessions and reset tokens. Returns count removed."""
|
||||
now = datetime.now(timezone.utc)
|
||||
count = 0
|
||||
with _db.transaction("admin:cleanup_expired"):
|
||||
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]
|
||||
|
||||
@@ -9,6 +9,7 @@ from fastapi.responses import FileResponse, RedirectResponse
|
||||
from fastapi_vue import Frontend
|
||||
|
||||
from paskia import globals
|
||||
from paskia.db import start_background, stop_background
|
||||
from paskia.fastapi import admin, api, auth_host, ws
|
||||
from paskia.fastapi.session import AUTH_COOKIE
|
||||
from paskia.util import hostutil, passphrase, vitedev
|
||||
@@ -32,7 +33,6 @@ async def lifespan(app: FastAPI): # pragma: no cover - startup path
|
||||
so that uvicorn reload / multiprocess workers inherit the settings.
|
||||
All keys are guaranteed to exist; values are already normalized by __main__.py.
|
||||
"""
|
||||
|
||||
config = json.loads(os.environ["PASKIA_CONFIG"])
|
||||
|
||||
try:
|
||||
@@ -54,7 +54,9 @@ async def lifespan(app: FastAPI): # pragma: no cover - startup path
|
||||
logging.getLogger("uvicorn.access").setLevel(logging.INFO)
|
||||
|
||||
await frontend.load()
|
||||
await start_background()
|
||||
yield
|
||||
await stop_background()
|
||||
|
||||
|
||||
app = FastAPI(lifespan=lifespan, redirect_slashes=False)
|
||||
|
||||
@@ -2,7 +2,6 @@ from typing import Generic, TypeVar
|
||||
|
||||
from paskia import db, remoteauth
|
||||
from paskia.bootstrap import bootstrap_if_needed
|
||||
from paskia.db import start_background
|
||||
from paskia.sansio import Passkey
|
||||
|
||||
T = TypeVar("T")
|
||||
@@ -64,10 +63,6 @@ async def init(
|
||||
|
||||
await bootstrap_if_needed()
|
||||
|
||||
# Start background flush/cleanup task after bootstrap
|
||||
|
||||
await start_background()
|
||||
|
||||
|
||||
# Global instances
|
||||
passkey = Manager[Passkey]("Passkey")
|
||||
|
||||
Reference in New Issue
Block a user