package console import ( "context" "log" "time" "github.com/carlosframework/platform/internal/plans" ) // plansMarkerRetry is the first wait between attempts; it doubles up to // plansMarkerRetryMax. A var so a test can shrink it. var plansMarkerRetry = 5 * time.Second const plansMarkerRetryMax = 5 * time.Minute // PublishPlansMarker tells boxes whether plans are on (plans 2). It runs once // per console start. With a catalog it makes sure control/plans.json is // enabled under this catalog's id; without one it touches nothing unless an // enabled marker is left over, which it turns off so boxes stop applying // limits within a pass. A self-hosted deployment that never configured a // catalog never gets a marker. func (s *Server) PublishPlansMarker(ctx context.Context) { if s.cfg.Releases == nil { return } // Retry until the marker is right: a bucket blip at start must not leave // boxes applying limits after the catalog was removed, or never applying // them after it was added (Astra plans-2 finding 1). wait := plansMarkerRetry for !s.publishPlansMarkerOnce(ctx) { select { case <-ctx.Done(): return case <-time.After(wait): } wait = min(2*wait, plansMarkerRetryMax) } } // publishPlansMarkerOnce makes one attempt and reports whether the marker is // now as it should be (including "nothing to do"). func (s *Server) publishPlansMarkerOnce(ctx context.Context) bool { cur, etag, err := plans.GetMarker(ctx, s.cfg.Releases) if err != nil { log.Printf("console: plans marker: read: %v", err) return false } want := plans.Marker{UpdatedAt: time.Now().UTC().Truncate(time.Second)} if cat := s.cfg.PlanCatalog; cat != nil { if cur != nil && cur.Enabled && cur.CatalogID == cat.ID() { return true } want.Enabled, want.CatalogID = true, cat.ID() } else if cur == nil || !cur.Enabled { return true } if _, err := plans.PutMarker(ctx, s.cfg.Releases, &want, etag); err != nil { log.Printf("console: plans marker: write: %v", err) return false } return true }