diff --git a/internal/report/snapshots.go b/internal/report/snapshots.go index 261f88e..ed66053 100644 --- a/internal/report/snapshots.go +++ b/internal/report/snapshots.go @@ -554,7 +554,7 @@ func CreateTableReport(logger *slog.Logger, Database db.Database, ctx context.Co if err := db.ValidateTableName(tableName); err != nil { return nil, err } - reportCfg := reloadReportSettingsForReport(logger, cfg) + reportCfg := reloadReportSettingsForReport(ctx, logger, cfg) start := time.Now() logger.Debug("Create table report start", "table", tableName) @@ -792,13 +792,17 @@ func CreateTableReport(logger *slog.Logger, Database db.Database, ctx context.Co return buffer.Bytes(), nil } -func reloadReportSettingsForReport(logger *slog.Logger, cfg *settings.Settings) *settings.Settings { +func reloadReportSettingsForReport(ctx context.Context, logger *slog.Logger, cfg *settings.Settings) *settings.Settings { if cfg == nil { return nil } if strings.TrimSpace(cfg.SettingsPath) == "" { return cfg } + if settings.IsReloadedInContext(ctx, cfg) { + logger.Debug("settings already reloaded for current run; using in-memory settings", "settings_file", cfg.SettingsPath) + return cfg + } reloaded := settings.New(logger, cfg.SettingsPath) if err := reloaded.ReadYMLSettings(); err != nil { diff --git a/internal/settings/context.go b/internal/settings/context.go new file mode 100644 index 0000000..b9f45d1 --- /dev/null +++ b/internal/settings/context.go @@ -0,0 +1,28 @@ +package settings + +import "context" + +type reloadedContextKey struct{} + +// MarkReloadedInContext marks that a given Settings instance has been refreshed in this context flow. +func MarkReloadedInContext(ctx context.Context, cfg *Settings) context.Context { + if ctx == nil { + ctx = context.Background() + } + if cfg == nil { + return ctx + } + return context.WithValue(ctx, reloadedContextKey{}, cfg) +} + +// IsReloadedInContext reports whether this context flow already refreshed the provided Settings. +func IsReloadedInContext(ctx context.Context, cfg *Settings) bool { + if ctx == nil || cfg == nil { + return false + } + marked, ok := ctx.Value(reloadedContextKey{}).(*Settings) + if !ok || marked == nil { + return false + } + return marked == cfg +} diff --git a/internal/tasks/dailyAggregate.go b/internal/tasks/dailyAggregate.go index 9658872..566c153 100644 --- a/internal/tasks/dailyAggregate.go +++ b/internal/tasks/dailyAggregate.go @@ -15,12 +15,17 @@ import ( "vctp/db" "vctp/internal/metrics" "vctp/internal/report" + "vctp/internal/settings" ) // RunVcenterDailyAggregate summarizes hourly snapshots into a daily summary table. func (c *CronTask) RunVcenterDailyAggregate(ctx context.Context, logger *slog.Logger) (err error) { jobTimeout := durationFromSeconds(c.Settings.Values.Settings.DailyJobTimeoutSeconds, 15*time.Minute) return c.runAggregateJob(ctx, "daily_aggregate", jobTimeout, func(jobCtx context.Context) error { + if err := c.Settings.ReadYMLSettings(); err != nil { + return err + } + jobCtx = settings.MarkReloadedInContext(jobCtx, c.Settings) startedAt := time.Now() defer func() { logger.Info("Daily summary job finished", "duration", time.Since(startedAt)) diff --git a/internal/tasks/inventorySnapshots.go b/internal/tasks/inventorySnapshots.go index 28cf44c..fc1fe66 100644 --- a/internal/tasks/inventorySnapshots.go +++ b/internal/tasks/inventorySnapshots.go @@ -16,6 +16,7 @@ import ( "vctp/db/queries" "vctp/internal/metrics" "vctp/internal/report" + "vctp/internal/settings" "vctp/internal/utils" "vctp/internal/vcenter" @@ -116,8 +117,11 @@ func (c *CronTask) RunVcenterSnapshotHourly(ctx context.Context, logger *slog.Lo // Best-effort cleanup of legacy IsPresent columns to simplify inserts. c.dropLegacyIsPresentColumns(jobCtx) - // reload settings in case vcenter list has changed - c.Settings.ReadYMLSettings() + // Reload settings once for this run (for example, in case vCenter list has changed). + if err := c.Settings.ReadYMLSettings(); err != nil { + return err + } + ctx = settings.MarkReloadedInContext(ctx, c.Settings) if c.FirstHourlySnapshotCheck { if err := report.EnsureSnapshotRegistry(ctx, c.Database); err != nil { diff --git a/internal/tasks/monthlyAggregate.go b/internal/tasks/monthlyAggregate.go index aa60ed5..7f491e7 100644 --- a/internal/tasks/monthlyAggregate.go +++ b/internal/tasks/monthlyAggregate.go @@ -14,12 +14,17 @@ import ( "vctp/db" "vctp/internal/metrics" "vctp/internal/report" + "vctp/internal/settings" ) // RunVcenterMonthlyAggregate summarizes the previous month's daily snapshots. func (c *CronTask) RunVcenterMonthlyAggregate(ctx context.Context, logger *slog.Logger) (err error) { jobTimeout := durationFromSeconds(c.Settings.Values.Settings.MonthlyJobTimeoutSeconds, 20*time.Minute) return c.runAggregateJob(ctx, "monthly_aggregate", jobTimeout, func(jobCtx context.Context) error { + if err := c.Settings.ReadYMLSettings(); err != nil { + return err + } + jobCtx = settings.MarkReloadedInContext(jobCtx, c.Settings) startedAt := time.Now() defer func() { logger.Info("Monthly summary job finished", "duration", time.Since(startedAt))