github.com/letsencrypt/boulder@v0.20251208.0/crl/updater/continuous.go (about) 1 package updater 2 3 import ( 4 "context" 5 "math/rand/v2" 6 "sync" 7 "time" 8 9 "github.com/letsencrypt/boulder/crl" 10 "github.com/letsencrypt/boulder/issuance" 11 ) 12 13 // Run causes the crlUpdater to enter its processing loop. It starts one 14 // goroutine for every shard it intends to update, each of which will wake at 15 // the appropriate interval. 16 func (cu *crlUpdater) Run(ctx context.Context) error { 17 var wg sync.WaitGroup 18 19 shardWorker := func(issuerNameID issuance.NameID, shardIdx int) { 20 defer wg.Done() 21 22 // Wait for a random number of nanoseconds less than the updatePeriod, so 23 // that process restarts do not skip or delay shards deterministically. 24 waitTimer := time.NewTimer(time.Duration(rand.Int64N(cu.updatePeriod.Nanoseconds()))) 25 defer waitTimer.Stop() 26 select { 27 case <-waitTimer.C: 28 // Continue to ticker loop 29 case <-ctx.Done(): 30 return 31 } 32 33 // Do work, then sleep for updatePeriod. Rinse, and repeat. 34 ticker := time.NewTicker(cu.updatePeriod) 35 defer ticker.Stop() 36 for { 37 // Check for context cancellation before we do any real work, in case we 38 // overran the last tick and both cases were selectable at the same time. 39 if ctx.Err() != nil { 40 return 41 } 42 43 atTime := cu.clk.Now() 44 err := cu.updateShardWithRetry(ctx, atTime, issuerNameID, shardIdx) 45 if err != nil { 46 // We only log, rather than return, so that the long-lived process can 47 // continue and try again at the next tick. 48 cu.log.AuditErrf( 49 "Generating CRL failed: id=[%s] err=[%s]", 50 crl.Id(issuerNameID, shardIdx, crl.Number(atTime)), err) 51 } 52 53 select { 54 case <-ticker.C: 55 continue 56 case <-ctx.Done(): 57 return 58 } 59 } 60 } 61 62 // Start one shard worker per shard this updater is responsible for. 63 for _, issuer := range cu.issuers { 64 for i := 1; i <= cu.numShards; i++ { 65 wg.Add(1) 66 go shardWorker(issuer.NameID(), i) 67 } 68 } 69 70 // Wait for all of the shard workers to exit, which will happen when their 71 // contexts are cancelled, probably by a SIGTERM. 72 wg.Wait() 73 return ctx.Err() 74 }