@@ -361,49 +361,32 @@ func (c *StoreReconciler) ReconcilePreset(ctx context.Context, ps prebuilds.Pres
361
361
slog .F ("preset_name" , ps .Preset .Name ),
362
362
)
363
363
364
- if ps .IsHardLimited {
364
+ // If the preset was previously hard-limited, log it and exit early.
365
+ if ps .Preset .PrebuildStatus .PrebuildStatus == database .PrebuildStatusHardLimited {
365
366
logger .Warn (ctx , "skipping hard limited preset" , slog .F ("preset_id" , ps .Preset .ID ), slog .F ("name" , ps .Preset .Name ))
367
+ return nil
368
+ }
366
369
367
- // TODO: rename ctx?
368
- // nolint:gocritic // Necessary to query all the required data.
369
- ctx := dbauthz .AsSystemRestricted (ctx )
370
-
371
- // TODO(yevhenii): move into separate function
372
- // Send notification to template admins.
373
- if c .notifEnq == nil {
374
- c .logger .Warn (ctx , "notification enqueuer not set, cannot send resource replacement notification(s)" )
375
- return nil
376
- }
370
+ // If the preset reached the hard failure limit for the first time during this iteration:
371
+ // - Mark it as hard-limited in the database
372
+ // - Send notifications to template admins
373
+ if ps .IsHardLimited {
374
+ logger .Warn (ctx , "skipping hard limited preset" , slog .F ("preset_id" , ps .Preset .ID ), slog .F ("name" , ps .Preset .Name ))
377
375
378
- // TODO(yevhenii): remove owner from the list
379
- templateAdmins , err := c .store .GetUsers (ctx , database.GetUsersParams {
380
- RbacRole : []string {codersdk .RoleTemplateAdmin , codersdk .RoleOwner },
376
+ err := c .store .UpdatePrebuildStatus (ctx , database.UpdatePrebuildStatusParams {
377
+ Status : database.NullPrebuildStatus {
378
+ PrebuildStatus : database .PrebuildStatusHardLimited ,
379
+ Valid : true ,
380
+ },
381
+ PresetID : ps .Preset .ID ,
381
382
})
382
383
if err != nil {
383
- return xerrors . Errorf ( "fetch template admins: %w" , err )
384
+ return err
384
385
}
385
386
386
- for _ , templateAdmin := range templateAdmins {
387
- if _ , err := c .notifEnq .EnqueueWithData (ctx , templateAdmin .ID , notifications .PrebuildFailureLimitReached ,
388
- map [string ]string {
389
- "org" : ps .Preset .OrganizationName ,
390
- "template" : ps .Preset .TemplateName ,
391
- "template_version" : ps .Preset .TemplateVersionName ,
392
- "preset" : ps .Preset .Name ,
393
- },
394
- map [string ]any {},
395
- "prebuilds_reconciler" ,
396
- // Associate this notification with all the related entities.
397
- ps .Preset .TemplateID , ps .Preset .TemplateVersionID , ps .Preset .ID ,
398
- ); err != nil {
399
- c .logger .Error (ctx ,
400
- "failed to send notification" ,
401
- slog .Error (err ),
402
- slog .F ("template_admin_id" , templateAdmin .ID .String ()),
403
- )
404
-
405
- continue
406
- }
387
+ err = c .notifyPrebuildFailureLimitReached (ctx , ps )
388
+ if err != nil {
389
+ return err
407
390
}
408
391
409
392
return nil
@@ -502,6 +485,52 @@ func (c *StoreReconciler) ReconcilePreset(ctx context.Context, ps prebuilds.Pres
502
485
}
503
486
}
504
487
488
+ func (c * StoreReconciler ) notifyPrebuildFailureLimitReached (ctx context.Context , ps prebuilds.PresetSnapshot ) error {
489
+ // TODO: rename ctx?
490
+ // nolint:gocritic // Necessary to query all the required data.
491
+ ctx = dbauthz .AsSystemRestricted (ctx )
492
+
493
+ // TODO(yevhenii): move into separate function
494
+ // Send notification to template admins.
495
+ if c .notifEnq == nil {
496
+ c .logger .Warn (ctx , "notification enqueuer not set, cannot send resource replacement notification(s)" )
497
+ return nil
498
+ }
499
+
500
+ // TODO(yevhenii): remove owner from the list
501
+ templateAdmins , err := c .store .GetUsers (ctx , database.GetUsersParams {
502
+ RbacRole : []string {codersdk .RoleTemplateAdmin , codersdk .RoleOwner },
503
+ })
504
+ if err != nil {
505
+ return xerrors .Errorf ("fetch template admins: %w" , err )
506
+ }
507
+
508
+ for _ , templateAdmin := range templateAdmins {
509
+ if _ , err := c .notifEnq .EnqueueWithData (ctx , templateAdmin .ID , notifications .PrebuildFailureLimitReached ,
510
+ map [string ]string {
511
+ "org" : ps .Preset .OrganizationName ,
512
+ "template" : ps .Preset .TemplateName ,
513
+ "template_version" : ps .Preset .TemplateVersionName ,
514
+ "preset" : ps .Preset .Name ,
515
+ },
516
+ map [string ]any {},
517
+ "prebuilds_reconciler" ,
518
+ // Associate this notification with all the related entities.
519
+ ps .Preset .TemplateID , ps .Preset .TemplateVersionID , ps .Preset .ID ,
520
+ ); err != nil {
521
+ c .logger .Error (ctx ,
522
+ "failed to send notification" ,
523
+ slog .Error (err ),
524
+ slog .F ("template_admin_id" , templateAdmin .ID .String ()),
525
+ )
526
+
527
+ continue
528
+ }
529
+ }
530
+
531
+ return nil
532
+ }
533
+
505
534
func (c * StoreReconciler ) CalculateActions (ctx context.Context , snapshot prebuilds.PresetSnapshot ) (* prebuilds.ReconciliationActions , error ) {
506
535
if ctx .Err () != nil {
507
536
return nil , ctx .Err ()
0 commit comments