From a94039079162b9cf64a585baf4b586342479db73 Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Sun, 26 Jul 2026 13:24:44 +0100 Subject: [PATCH] feat(admin): reconciler marks reaped instances deleted Without this the row stays active forever, the reconciler re-logs the same miss every fifteen minutes, and the lifecycle sweep keeps emailing about an instance that no longer exists. Co-Authored-By: Claude Opus 5 --- admin/internal/inject/inject.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/admin/internal/inject/inject.go b/admin/internal/inject/inject.go index 23bec5b..a1029dc 100644 --- a/admin/internal/inject/inject.go +++ b/admin/internal/inject/inject.go @@ -7,6 +7,7 @@ package inject import ( "context" + "errors" "fmt" "log" "time" @@ -16,6 +17,7 @@ import ( "github.com/mrhid6/vantage/shared/license" sharedmodels "github.com/mrhid6/vantage/shared/models" "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" ) // ReconcileInterval is how often every cloud instance is compared against what @@ -103,6 +105,19 @@ func Reconcile(ctx context.Context) (checked, repaired int, err error) { var remote sharedmodels.Instance if err := db.Control("instances").FindOne(ctx, bson.M{"instance_id": inst.InstanceID}).Decode(&remote); err != nil { + // The control plane's reaper deletes lapsed Free instances. Record + // that here rather than re-logging it every fifteen minutes forever, + // and so the lifecycle sweep stops emailing about it. + if errors.Is(err, mongo.ErrNoDocuments) { + if _, uErr := db.Admin("admin_instances").UpdateOne(ctx, + bson.M{"instance_id": inst.InstanceID}, + bson.M{"$set": bson.M{"status": models.StatusDeleted}}); uErr != nil { + log.Printf("reconcile: mark %s deleted: %v", inst.InstanceID, uErr) + } else { + log.Printf("reconcile: instance %s is gone from the control plane; marked deleted", inst.InstanceID) + } + continue + } log.Printf("reconcile: no control-plane instance %s: %v", inst.InstanceID, err) continue }