Debug JSONL updates.
This commit is contained in:
+4
-13
@@ -47,23 +47,16 @@ def cleanup() -> None:
|
|||||||
|
|
||||||
async def flush() -> None:
|
async def flush() -> None:
|
||||||
"""Write all pending database changes to disk."""
|
"""Write all pending database changes to disk."""
|
||||||
import sys
|
|
||||||
from paskia.db.operations import _db
|
from paskia.db.operations import _db
|
||||||
|
|
||||||
if _db is None:
|
if _db is None:
|
||||||
_logger.warning("flush() called but _db is None")
|
_logger.warning("flush() called but _db is None")
|
||||||
print("[DB] flush() called but _db is None", file=sys.stderr)
|
|
||||||
return
|
return
|
||||||
pending_count = len(_db._pending_changes)
|
|
||||||
if pending_count > 0:
|
|
||||||
print(f"[DB] flush() called with {pending_count} pending changes, db_path={_db.db_path}", file=sys.stderr)
|
|
||||||
await flush_changes(_db.db_path, _db._pending_changes)
|
await flush_changes(_db.db_path, _db._pending_changes)
|
||||||
|
|
||||||
|
|
||||||
async def _background_loop():
|
async def _background_loop():
|
||||||
"""Background task that periodically flushes changes and cleans up."""
|
"""Background task that periodically flushes changes and cleans up."""
|
||||||
import sys
|
|
||||||
print("[DB] Background loop starting", file=sys.stderr)
|
|
||||||
_logger.info("Background loop starting")
|
_logger.info("Background loop starting")
|
||||||
# Run cleanup immediately on startup to clear old expired items
|
# Run cleanup immediately on startup to clear old expired items
|
||||||
cleanup()
|
cleanup()
|
||||||
@@ -94,13 +87,12 @@ async def _background_loop():
|
|||||||
|
|
||||||
async def start_background():
|
async def start_background():
|
||||||
"""Start the background flush/cleanup task."""
|
"""Start the background flush/cleanup task."""
|
||||||
import sys
|
|
||||||
global _background_task
|
global _background_task
|
||||||
|
|
||||||
# Check if task exists but is no longer running (e.g., after uvicorn reload)
|
# Check if task exists but is no longer running (e.g., after uvicorn reload)
|
||||||
if _background_task is not None:
|
if _background_task is not None:
|
||||||
if _background_task.done():
|
if _background_task.done():
|
||||||
print(f"[DB] Previous background task was done, restarting", file=sys.stderr)
|
_logger.debug("Previous background task was done, restarting")
|
||||||
_background_task = None
|
_background_task = None
|
||||||
else:
|
else:
|
||||||
# Task exists and is running - but might be in a dead event loop
|
# Task exists and is running - but might be in a dead event loop
|
||||||
@@ -109,18 +101,17 @@ async def start_background():
|
|||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
task_loop = _background_task.get_loop()
|
task_loop = _background_task.get_loop()
|
||||||
if loop is not task_loop:
|
if loop is not task_loop:
|
||||||
print(f"[DB] Background task in different event loop, restarting", file=sys.stderr)
|
_logger.debug("Background task in different event loop, restarting")
|
||||||
_background_task = None
|
_background_task = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[DB] Error checking background task loop: {e}, restarting", file=sys.stderr)
|
_logger.debug("Error checking background task loop: %s, restarting", e)
|
||||||
_background_task = None
|
_background_task = None
|
||||||
|
|
||||||
if _background_task is None:
|
if _background_task is None:
|
||||||
_background_task = asyncio.create_task(_background_loop())
|
_background_task = asyncio.create_task(_background_loop())
|
||||||
_logger.info("Database background task started")
|
_logger.info("Database background task started")
|
||||||
print("[DB] Database background task started", file=sys.stderr)
|
|
||||||
else:
|
else:
|
||||||
print(f"[DB] Background task already running: {_background_task}", file=sys.stderr)
|
_logger.debug("Background task already running: %s", _background_task)
|
||||||
|
|
||||||
|
|
||||||
async def stop_background():
|
async def stop_background():
|
||||||
|
|||||||
+1
-3
@@ -119,11 +119,9 @@ async def flush_changes(
|
|||||||
# Append all lines in a single write (binary mode for Windows compatibility)
|
# Append all lines in a single write (binary mode for Windows compatibility)
|
||||||
async with aiofiles.open(db_path, "ab") as f:
|
async with aiofiles.open(db_path, "ab") as f:
|
||||||
await f.write(b"\n".join(lines) + b"\n")
|
await f.write(b"\n".join(lines) + b"\n")
|
||||||
_logger.info(
|
_logger.debug(
|
||||||
"Flushed %d change(s) to %s", len(changes_to_write), db_path
|
"Flushed %d change(s) to %s", len(changes_to_write), db_path
|
||||||
)
|
)
|
||||||
import sys
|
|
||||||
print(f"[DB] Flushed {len(changes_to_write)} change(s) to {db_path}", file=sys.stderr)
|
|
||||||
return True
|
return True
|
||||||
except OSError:
|
except OSError:
|
||||||
_logger.exception("Failed to flush database changes")
|
_logger.exception("Failed to flush database changes")
|
||||||
|
|||||||
+11
-24
@@ -101,15 +101,17 @@ class DB:
|
|||||||
create_change_record(self._current_actor, diff)
|
create_change_record(self._current_actor, diff)
|
||||||
)
|
)
|
||||||
self._previous_builtins = current
|
self._previous_builtins = current
|
||||||
_logger.info(
|
# Log the change with user display name if available
|
||||||
"Queued change by %s, %d pending",
|
actor_display = self._current_actor
|
||||||
self._current_actor,
|
if self._current_actor not in ("system", "expiry", "migrate"):
|
||||||
len(self._pending_changes),
|
try:
|
||||||
)
|
user_uuid = UUID(self._current_actor)
|
||||||
import sys
|
if user_uuid in self._data.users:
|
||||||
|
actor_display = self._data.users[user_uuid].display_name
|
||||||
|
except (ValueError, KeyError):
|
||||||
|
pass
|
||||||
import json
|
import json
|
||||||
print(f"[DB] Queued change by {self._current_actor}, {len(self._pending_changes)} pending", file=sys.stderr)
|
_logger.info("DB change by %s: %s", actor_display, json.dumps(diff, default=str))
|
||||||
print(f"[DB] diff: {json.dumps(diff, default=str)}", file=sys.stderr)
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def transaction(self, actor: str = "system"):
|
def transaction(self, actor: str = "system"):
|
||||||
@@ -173,10 +175,8 @@ def build_role(uuid: UUID) -> Role:
|
|||||||
|
|
||||||
|
|
||||||
def build_org(uuid: UUID, include_roles: bool = False) -> Org:
|
def build_org(uuid: UUID, include_roles: bool = False) -> Org:
|
||||||
import sys
|
|
||||||
o = _db._data.orgs[uuid]
|
o = _db._data.orgs[uuid]
|
||||||
perm_scopes = [p.scope for p in _db._data.permissions.values() if uuid in p.orgs]
|
perm_scopes = [p.scope for p in _db._data.permissions.values() if uuid in p.orgs]
|
||||||
print(f"[DB] build_org({uuid}): permissions={perm_scopes}", file=sys.stderr)
|
|
||||||
org = Org(uuid=uuid, display_name=o.display_name, permissions=perm_scopes)
|
org = Org(uuid=uuid, display_name=o.display_name, permissions=perm_scopes)
|
||||||
if include_roles:
|
if include_roles:
|
||||||
org.roles = [
|
org.roles = [
|
||||||
@@ -528,9 +528,8 @@ def rename_permission(
|
|||||||
"""Rename a permission's scope. The UUID remains the same.
|
"""Rename a permission's scope. The UUID remains the same.
|
||||||
|
|
||||||
Also updates all role references to use the new scope.
|
Also updates all role references to use the new scope.
|
||||||
|
Note: Scopes do not need to be unique (same scope with different domains is valid).
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
|
|
||||||
# Find permission by old scope
|
# Find permission by old scope
|
||||||
key = None
|
key = None
|
||||||
for pid, p in _db._data.permissions.items():
|
for pid, p in _db._data.permissions.items():
|
||||||
@@ -540,15 +539,6 @@ def rename_permission(
|
|||||||
if not key:
|
if not key:
|
||||||
raise ValueError(f"Permission with scope '{old_scope}' not found")
|
raise ValueError(f"Permission with scope '{old_scope}' not found")
|
||||||
|
|
||||||
# Check if new scope already exists (on a different permission)
|
|
||||||
for pid, p in _db._data.permissions.items():
|
|
||||||
if p.scope == new_scope and pid != key:
|
|
||||||
raise ValueError(f"Permission with scope '{new_scope}' already exists")
|
|
||||||
|
|
||||||
# Debug: Print orgs before change
|
|
||||||
print(f"[DB] rename_permission: {old_scope} -> {new_scope}", file=sys.stderr)
|
|
||||||
print(f"[DB] orgs BEFORE: {_db._data.permissions[key].orgs}", file=sys.stderr)
|
|
||||||
|
|
||||||
with _db.transaction(actor):
|
with _db.transaction(actor):
|
||||||
# Update the permission
|
# Update the permission
|
||||||
_db._data.permissions[key].scope = new_scope
|
_db._data.permissions[key].scope = new_scope
|
||||||
@@ -562,9 +552,6 @@ def rename_permission(
|
|||||||
del r.permissions[old_scope]
|
del r.permissions[old_scope]
|
||||||
r.permissions[new_scope] = True
|
r.permissions[new_scope] = True
|
||||||
|
|
||||||
# Debug: Print orgs after change
|
|
||||||
print(f"[DB] orgs AFTER: {_db._data.permissions[key].orgs}", file=sys.stderr)
|
|
||||||
|
|
||||||
|
|
||||||
def delete_permission(uuid: str | UUID, actor: str = "system") -> None:
|
def delete_permission(uuid: str | UUID, actor: str = "system") -> None:
|
||||||
"""Delete a permission."""
|
"""Delete a permission."""
|
||||||
|
|||||||
Reference in New Issue
Block a user