From 5706e3d2af0c4e8b3829d12643b90332ddcc89ee Mon Sep 17 00:00:00 2001 From: Kieran Klukas Date: Tue, 16 Jun 2026 12:15:11 -0400 Subject: [PATCH] feat: prune old models --- server/db/queries/models_catalog.sql | 5 +++++ server/internal/pool/models_refresher.go | 10 +++++++++- server/internal/store/models_catalog.sql.go | 21 +++++++++++++++++++++ server/internal/store/querier.go | 3 +++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/server/db/queries/models_catalog.sql b/server/db/queries/models_catalog.sql index 0d782d6..c202e38 100644 --- a/server/db/queries/models_catalog.sql +++ b/server/db/queries/models_catalog.sql @@ -27,3 +27,8 @@ ORDER BY tier ASC, label ASC; -- name: GetModelCatalogRefreshedAt :one -- Oldest refreshed_at across all models — tells us when the catalog is stale. SELECT COALESCE(MIN(refreshed_at), 0) FROM models_catalog; + +-- name: PruneStaleModels :execrows +-- Delete models for a provider prefix that weren't refreshed in the current cycle. +-- The first arg is the LIKE pattern (e.g. "nvidia/%"). +DELETE FROM models_catalog WHERE id LIKE ? AND refreshed_at < ?; diff --git a/server/internal/pool/models_refresher.go b/server/internal/pool/models_refresher.go index 0f6c3b4..3dc45d4 100644 --- a/server/internal/pool/models_refresher.go +++ b/server/internal/pool/models_refresher.go @@ -70,6 +70,7 @@ func (r *ModelsRefresher) refreshAll(ctx context.Context) { } fetchCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + now := time.Now().Unix() models, err := fetcher.FetchModels(fetchCtx, r.httpClient, p.BaseURL, apiKey) cancel() @@ -85,7 +86,14 @@ func (r *ModelsRefresher) refreshAll(ctx context.Context) { upserted++ } } + + // Prune models that no longer exist on this provider. + pruned, _ := r.q.PruneStaleModels(context.Background(), store.PruneStaleModelsParams{ + ID: p.ID + "/%", + RefreshedAt: now, + }) + r.log.Info("models refresher: catalog updated", - "provider", p.ID, "models", len(models), "upserted", upserted) + "provider", p.ID, "models", len(models), "upserted", upserted, "pruned", pruned) } } diff --git a/server/internal/store/models_catalog.sql.go b/server/internal/store/models_catalog.sql.go index ea8e497..b91fe9e 100644 --- a/server/internal/store/models_catalog.sql.go +++ b/server/internal/store/models_catalog.sql.go @@ -63,6 +63,27 @@ func (q *Queries) ListModelCatalog(ctx context.Context) ([]ModelsCatalog, error) return items, nil } +const pruneStaleModels = `-- name: PruneStaleModels :execrows +g; + +DELETE FROM models_catalog WHERE id LIKE ? AND refreshed_at < +` + +type PruneStaleModelsParams struct { + ID string `json:"id"` + RefreshedAt int64 `json:"refreshed_at"` +} + +// Delete models for a provider prefix that weren't refreshed in the current cycle. +// The first arg is the LIKE pattern (e.g. "nvidia/%"). +func (q *Queries) PruneStaleModels(ctx context.Context, arg PruneStaleModelsParams) (int64, error) { + result, err := q.db.ExecContext(ctx, pruneStaleModels, arg.ID, arg.RefreshedAt) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + const upsertModelCatalog = `-- name: UpsertModelCatalog :exec INSERT INTO models_catalog ( diff --git a/server/internal/store/querier.go b/server/internal/store/querier.go index 31927cb..9b2d0c0 100644 --- a/server/internal/store/querier.go +++ b/server/internal/store/querier.go @@ -174,6 +174,9 @@ type Querier interface { // Total pioneer credit limit across all active pool keys. PoolTotalBalance(ctx context.Context) (interface{}, error) PoolUserCount(ctx context.Context) (int64, error) + // Delete models for a provider prefix that weren't refreshed in the current cycle. + // The first arg is the LIKE pattern (e.g. "nvidia/%"). + PruneStaleModels(ctx context.Context, arg PruneStaleModelsParams) (int64, error) PutIdempotency(ctx context.Context, arg PutIdempotencyParams) error // Called after a request settles. Resets daily counter if the day rolled over. // today_day is the current UTC day (unix / 86400). -- 2.51.2