/** * Admin-facing compaction state transitions: preview, request, and clear. * * These operations are triggered by POST/DELETE on /admin/compact. * They read or mutate `compactionWantedAt` in DO storage but never * acquire or release compaction leases. */ import type { Logger } from "@/worker/common/logger"; import type { RepoStateSchema } from "../../repoState"; import { asTypedStorage } from "../../repoState"; import { loadCompactionContext, scheduleCompactionWake, type PreviewCompactionResult, type RequestCompactionResult, type ClearCompactionRequestResult, } from "./plan"; /** * Preview the current compaction plan without recording a request. * * Returns a concrete automatic plan only when a compactable tier has a safe * bounded source window. An overflowing tier can still report `blocked` when * automatic queue maintenance would exceed the configured in-code budget. */ export async function previewCompactionState(args: { ctx: DurableObjectState; env: Env; prefix: string; logger?: Logger; }): Promise { const context = await loadCompactionContext(args); const queued = typeof context.wantedAt === "number"; if (context.selection.status === "blocked") { args.logger?.warn("compaction:preview-blocked", { queued, reason: context.selection.blocked.reason, sourceTier: context.selection.blocked.sourceTier, activePackCount: context.selection.blocked.activePackCount, maxSourceObjects: context.selection.blocked.maxSourceObjects, maxSourceBytes: context.selection.blocked.maxSourceBytes, smallestWindowObjects: context.selection.blocked.smallestWindowObjects, smallestWindowBytes: context.selection.blocked.smallestWindowBytes, }); return { action: "preview", status: "blocked", queued, wantedAt: context.wantedAt, activeCatalog: context.activeCatalog, packCatalogVersion: context.packCatalogVersion, blocked: context.selection.blocked, reason: context.selection.blocked.reason, message: "Automatic compaction is blocked because no safe source-pack window fits the bounded maintenance budget.", }; } if (context.selection.status === "no_work") { args.logger?.info("compaction:preview-no-work", { reason: "below-threshold", queued, }); return { action: "preview", status: "no_work", queued, wantedAt: context.wantedAt, activeCatalog: context.activeCatalog, packCatalogVersion: context.packCatalogVersion, reason: "below-threshold", message: "The active pack catalog is already within the compaction policy.", }; } const plan = context.selection.plan; args.logger?.info("compaction:preview", { queued, sourceTier: plan.sourceTier, targetTier: plan.targetTier, sourceCount: plan.sourcePacks.length, }); return { action: "preview", status: "ok", queued, wantedAt: context.wantedAt, activeCatalog: context.activeCatalog, packCatalogVersion: context.packCatalogVersion, plan, message: "The active pack catalog has compactable tiers.", }; } /** * Record a compaction request and schedule background work. * * Only queues work when the active catalog has a bounded automatic plan. * Clears stale `compactionWantedAt` when no safe plan exists. */ export async function requestCompactionState(args: { ctx: DurableObjectState; env: Env; prefix: string; logger?: Logger; }): Promise { const context = await loadCompactionContext(args); if (context.selection.status === "blocked") { if (typeof context.wantedAt === "number") { await context.store.delete("compactionWantedAt"); } args.logger?.warn("compaction:request-blocked", { reason: context.selection.blocked.reason, sourceTier: context.selection.blocked.sourceTier, activePackCount: context.selection.blocked.activePackCount, maxSourceObjects: context.selection.blocked.maxSourceObjects, maxSourceBytes: context.selection.blocked.maxSourceBytes, smallestWindowObjects: context.selection.blocked.smallestWindowObjects, smallestWindowBytes: context.selection.blocked.smallestWindowBytes, }); return { action: "request", status: "blocked", queued: false, shouldEnqueue: false, activeCatalog: context.activeCatalog, packCatalogVersion: context.packCatalogVersion, blocked: context.selection.blocked, reason: context.selection.blocked.reason, message: "Automatic compaction is blocked because no safe source-pack window fits the bounded maintenance budget.", }; } if (context.selection.status === "no_work") { if (typeof context.wantedAt === "number") { await context.store.delete("compactionWantedAt"); } args.logger?.info("compaction:request-no-work", {}); return { action: "request", status: "no_work", queued: false, shouldEnqueue: false, activeCatalog: context.activeCatalog, packCatalogVersion: context.packCatalogVersion, reason: "below-threshold", message: "The active pack catalog is already within the compaction policy.", }; } const plan = context.selection.plan; const wantedAt = Date.now(); await context.store.put("compactionWantedAt", wantedAt); await scheduleCompactionWake(args.ctx, args.env); args.logger?.info("compaction:request", { wantedAt, sourceTier: plan.sourceTier, targetTier: plan.targetTier, sourceCount: plan.sourcePacks.length, }); return { action: "request", status: "queued", queued: true, shouldEnqueue: true, wantedAt, activeCatalog: context.activeCatalog, packCatalogVersion: context.packCatalogVersion, plan, message: "Recorded a compaction request for this repository and queued background work.", }; } /** Clear any recorded compaction request without affecting active leases. */ export async function clearCompactionRequestState(args: { ctx: DurableObjectState; logger?: Logger; }): Promise { const store = asTypedStorage(args.ctx.storage); const hadQueuedWork = typeof (await store.get("compactionWantedAt")) === "number"; await store.delete("compactionWantedAt"); args.logger?.info("compaction:clear", { hadQueuedWork, }); return { action: "cleared", cleared: hadQueuedWork, message: hadQueuedWork ? "Cleared the recorded compaction request." : "No recorded compaction request was present.", }; }