Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **fix(db):** Fresh installs no longer log a non-fatal `no such table: compression_run_telemetry` warning when retention cleanup runs before the lazily-created telemetry table exists ([#11802](https://github.com/diegosouzapw/OmniRoute/pull/11802)) — thanks @RaviTharuma
67 changes: 57 additions & 10 deletions src/lib/db/cleanup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
deleteAllFromTable,
deleteCallLogArtifacts,
deleteFromTableBefore,
tableExists,
type DeleteByPeriodTarget,
} from "./cleanup/usagePurge";

Expand Down Expand Up @@ -196,7 +197,9 @@ export async function cleanupMcpAudit(): Promise<CleanupResult> {
/**
* Clean up old config_audit_log based on retention settings.
*/
export async function cleanupConfigAudit(retentionDays = getRetentionSettings().configAudit): Promise<CleanupResult> {
export async function cleanupConfigAudit(
retentionDays = getRetentionSettings().configAudit
): Promise<CleanupResult> {
const db = getDbInstance();
const result: CleanupResult = { deleted: 0, errors: 0 };

Expand Down Expand Up @@ -237,7 +240,9 @@ export async function cleanupA2aEvents(): Promise<CleanupResult> {
const runResult = stmt.run(cutoffISO);
result.deleted = runResult.changes;

console.log(`[Cleanup] Deleted ${result.deleted} a2a_task_events older than ${retentionDays} days`);
console.log(
`[Cleanup] Deleted ${result.deleted} a2a_task_events older than ${retentionDays} days`
);
} catch (err: unknown) {
console.error("[Cleanup] Error cleaning a2a_task_events:", err);
result.errors++;
Expand Down Expand Up @@ -383,6 +388,8 @@ export async function cleanupCompressionRunTelemetry(): Promise<CleanupResult> {
const result: CleanupResult = { deleted: 0, errors: 0 };

try {
if (!tableExists("compression_run_telemetry")) return result;

const stmt = db.prepare("DELETE FROM compression_run_telemetry WHERE timestamp < ?");
const runResult = stmt.run(cutoffEpoch);
result.deleted = runResult.changes;
Expand Down Expand Up @@ -600,16 +607,56 @@ function isResetUsageHistoryPeriod(period: string): period is ResetUsageHistoryP
*/
const RESET_TARGETS: Array<DeleteByPeriodTarget & { resultKey: keyof ResetUsageHistoryResult }> = [
{ table: "usage_history", column: "timestamp", cutoff: "iso", resultKey: "deletedUsageHistory" },
{ table: "daily_usage_summary", column: "date", cutoff: "date", resultKey: "deletedDailySummary" },
{ table: "hourly_usage_summary", column: "date_hour", cutoff: "dateHour", resultKey: "deletedHourlySummary" },
{
table: "daily_usage_summary",
column: "date",
cutoff: "date",
resultKey: "deletedDailySummary",
},
{
table: "hourly_usage_summary",
column: "date_hour",
cutoff: "dateHour",
resultKey: "deletedHourlySummary",
},
{ table: "call_logs", column: "timestamp", cutoff: "iso", resultKey: "deletedCallLogs" },
{ table: "request_detail_logs", column: "timestamp", cutoff: "iso", resultKey: "deletedRequestDetailLogs" },
{
table: "request_detail_logs",
column: "timestamp",
cutoff: "iso",
resultKey: "deletedRequestDetailLogs",
},
{ table: "proxy_logs", column: "timestamp", cutoff: "iso", resultKey: "deletedProxyLogs" },
{ table: "relay_logs", column: "created_at", cutoff: "epochSeconds", resultKey: "deletedRelayLogs" },
{ table: "compression_analytics", column: "timestamp", cutoff: "iso", resultKey: "deletedCompressionAnalytics" },
{ table: "compression_run_telemetry", column: "timestamp", cutoff: "epochMs", resultKey: "deletedCompressionRunTelemetry" },
{ table: "routing_decisions", column: "created_at", cutoff: "iso", resultKey: "deletedRoutingDecisions" },
{ table: "quota_consumption", column: "updated_at", cutoff: "epochMs", resultKey: "deletedQuotaConsumption" },
{
table: "relay_logs",
column: "created_at",
cutoff: "epochSeconds",
resultKey: "deletedRelayLogs",
},
{
table: "compression_analytics",
column: "timestamp",
cutoff: "iso",
resultKey: "deletedCompressionAnalytics",
},
{
table: "compression_run_telemetry",
column: "timestamp",
cutoff: "epochMs",
resultKey: "deletedCompressionRunTelemetry",
},
{
table: "routing_decisions",
column: "created_at",
cutoff: "iso",
resultKey: "deletedRoutingDecisions",
},
{
table: "quota_consumption",
column: "updated_at",
cutoff: "epochMs",
resultKey: "deletedQuotaConsumption",
},
{ table: "token_ledger", column: "created_at", cutoff: "iso", resultKey: "deletedTokenLedger" },
];

Expand Down
24 changes: 24 additions & 0 deletions tests/unit/telemetry-auto-cleanup-6848.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,30 @@ test("#6848 cleanupCompressionRunTelemetry: deletes rows older than retention wi
assert.strictEqual(remaining.cnt, 1);
});

test("#6848 cleanupCompressionRunTelemetry: missing lazy table is an empty no-op", async () => {
getDbInstance()!.exec("DROP TABLE compression_run_telemetry");

const result = await cleanupCompressionRunTelemetry();

assert.deepStrictEqual(result, { deleted: 0, errors: 0 });
});

test("#6848 cleanupCompressionRunTelemetry: contains table lookup failures", async (t) => {
const db = getDbInstance()!;
const prepare = db.prepare.bind(db);
t.mock.method(db, "prepare", (sql: string) => {
if (sql.includes("sqlite_master")) {
throw new Error("injected table lookup failure");
}
return prepare(sql);
});
t.mock.method(console, "error", () => {});

const result = await cleanupCompressionRunTelemetry();

assert.deepStrictEqual(result, { deleted: 0, errors: 1 });
});

test("#6848 no rows deleted when all data is within retention window (calls all 4 real functions)", async () => {
ensureTelemetryTable();
const db = getDbInstance()!;
Expand Down
Loading