| 91 | } |
| 92 | |
| 93 | func NewStoreReconciler(store database.Store, |
| 94 | ps pubsub.Pubsub, |
| 95 | fileCache *files.Cache, |
| 96 | cfg codersdk.PrebuildsConfig, |
| 97 | logger slog.Logger, |
| 98 | clock quartz.Clock, |
| 99 | registerer prometheus.Registerer, |
| 100 | notifEnq notifications.Enqueuer, |
| 101 | buildUsageChecker *atomic.Pointer[wsbuilder.UsageChecker], |
| 102 | tracerProvider trace.TracerProvider, |
| 103 | maxDBConnections int, |
| 104 | workspaceBuilderMetrics *wsbuilder.Metrics, |
| 105 | ) *StoreReconciler { |
| 106 | reconciliationConcurrency := calculateReconciliationConcurrency(maxDBConnections) |
| 107 | |
| 108 | logger.Debug(context.Background(), "reconciler initialized", |
| 109 | slog.F("reconciliation_concurrency", reconciliationConcurrency), |
| 110 | slog.F("max_db_connections", maxDBConnections)) |
| 111 | |
| 112 | reconciler := &StoreReconciler{ |
| 113 | store: store, |
| 114 | pubsub: ps, |
| 115 | fileCache: fileCache, |
| 116 | logger: logger, |
| 117 | cfg: cfg, |
| 118 | clock: clock, |
| 119 | registerer: registerer, |
| 120 | notifEnq: notifEnq, |
| 121 | buildUsageChecker: buildUsageChecker, |
| 122 | tracer: tracerProvider.Tracer(tracing.TracerName), |
| 123 | done: make(chan struct{}, 1), |
| 124 | provisionNotifyCh: make(chan database.ProvisionerJob, 10), |
| 125 | reconciliationConcurrency: reconciliationConcurrency, |
| 126 | workspaceBuilderMetrics: workspaceBuilderMetrics, |
| 127 | } |
| 128 | |
| 129 | if registerer != nil { |
| 130 | reconciler.metrics = NewMetricsCollector(store, logger, reconciler) |
| 131 | if err := registerer.Register(reconciler.metrics); err != nil { |
| 132 | // If the registerer fails to register the metrics collector, it's not fatal. |
| 133 | logger.Error(context.Background(), "failed to register prometheus metrics", slog.Error(err)) |
| 134 | } |
| 135 | |
| 136 | factory := promauto.With(registerer) |
| 137 | reconciler.reconciliationDuration = factory.NewHistogram(prometheus.HistogramOpts{ |
| 138 | Namespace: "coderd", |
| 139 | Subsystem: "prebuilds", |
| 140 | Name: "reconciliation_duration_seconds", |
| 141 | Help: "Duration of each prebuilds reconciliation cycle.", |
| 142 | Buckets: prometheus.DefBuckets, |
| 143 | }) |
| 144 | } |
| 145 | |
| 146 | return reconciler |
| 147 | } |
| 148 | |
| 149 | // calculateReconciliationConcurrency determines the number of concurrent |
| 150 | // goroutines for preset reconciliation. Each preset may perform multiple |