Store execution traces in a new request_traces table

One row per execution holding its span tree as JSONB, linked to Logs rows
by request, message, activity and workflow-run ids. message_id cascades so
deleting or truncating a conversation drops its traces; a daily beat task
enforces TRACES_RETENTION_DAYS.
This commit is contained in:
arc53-machine committed 2026-09-23 17:19:54 +01:00
1 parent f6269c483f
commit f3f817b1e8
7 files changed
+686 -10

No files matched your search

+29
View File
@@ -608,6 +608,11 @@ def setup_periodic_tasks(sender, **kwargs):
cleanup_guardrail_events.s(),
name="cleanup-guardrail-events",
)
sender.add_periodic_task(
timedelta(hours=24),
cleanup_traces.s(),
name="cleanup-traces",
)
sender.add_periodic_task(
timedelta(hours=24),
cleanup_orphan_memories.s(),
@@ -827,6 +832,30 @@ def cleanup_guardrail_events(self):
return {"deleted": deleted, "ttl_days": ttl_days}
@celery.task(bind=True, acks_late=False)
def cleanup_traces(self):
"""Delete ``request_traces`` rows older than ``TRACES_RETENTION_DAYS``.
Every chat turn, scheduled run and search writes a trace, and each one
carries content previews, so the table is bounded by a retention window
like the other per-request journals.
"""
from docsgpt.core.settings import settings
if not settings.POSTGRES_URI:
return {"deleted": 0, "skipped": "POSTGRES_URI not set"}
from docsgpt.storage.db.engine import get_engine
from docsgpt.storage.db.repositories.request_traces import (
RequestTracesRepository,
)
ttl_days = settings.TRACES_RETENTION_DAYS
engine = get_engine()
with engine.begin() as conn:
deleted = RequestTracesRepository(conn).purge_older_than(ttl_days)
return {"deleted": deleted, "ttl_days": ttl_days}
@celery.task(bind=True, acks_late=False)
def cleanup_orphan_memories(self):
"""Sweep orphan memories left by the 0009 FK-to-trigger orphan window.