(ctx context.Context)
| 286 | queueNoMatch = false |
| 287 | b.metrics.queueSize.WithLabelValues(pkg.FullRepo, "queued").Dec() |
| 288 | b.metrics.queueSize.WithLabelValues(pkg.FullRepo, "building").Inc() |
| 289 | |
| 290 | go func(pkg *ProtoPackage) { |
| 291 | defer b.buildWG.Done() |
| 292 | dur, err := pkg.build(ctx) |
| 293 | b.metrics.queueSize.WithLabelValues(pkg.FullRepo, "building").Dec() |
| 294 | switch { |
| 295 | case err == nil: |
| 296 | log.Infof("[Q] build successful: %s->%s (%s)", pkg.FullRepo, pkg.Pkgbase, dur) |
| 297 | b.metrics.queueSize.WithLabelValues(pkg.FullRepo, "built").Inc() |
| 298 | case ctx.Err() != nil: |
| 299 | // A SIGTERM says nothing about the package, so it must not delete |
| 300 | // the published build, for the same reason build()'s isolation-setup |
| 301 | // path returns ErrorNotEligible. Load-bearing because waitForBuilds keeps |
| 302 | // the process alive long enough for the purge below to be picked up |
| 303 | // and to run to completion. Checked on ctx rather than the error, |
| 304 | // which arrives wrapped from setupBuildDir. |
| 305 | log.Infof("[Q] build of %s->%s interrupted by shutdown, leaving the published version in place", |
| 306 | pkg.FullRepo, pkg.Pkgbase) |
| 307 | case !errors.Is(err, ErrorNotEligible): |
| 308 | log.Warningf("[Q] error building package %s->%s in %s: %s", pkg.FullRepo, pkg.Pkgbase, dur, err) |
| 309 | b.repoPurge[pkg.FullRepo] <- []*ProtoPackage{pkg} |
| 310 | } |
| 311 | doneQLock.Lock() |
| 312 | b.buildingLock.Lock() |
| 313 | doneQ = append(doneQ, pkg) |
| 314 | |
| 315 | // pointer identity, not a key comparison: admission keys the build |
| 316 | // slot on (Pkgbase, March) and this is the same object that was |
| 317 | // appended, so matching on identity keeps the two from drifting |
| 318 | for i := range b.building { |
| 319 | if b.building[i] == pkg { |
| 320 | b.building = append(b.building[:i], b.building[i+1:]...) |
| 321 | break |
| 322 | } |
| 323 | } |
| 324 | doneQLock.Unlock() |
| 325 | b.buildingLock.Unlock() |
| 326 | select { |
| 327 | case b.queueSignal <- struct{}{}: |
| 328 | default: |
| 329 | } |
| 330 | }(pkg) |
| 331 | } |
| 332 | } else { |
| 333 | log.Debugf("[Q] memory/build limit reached, waiting for package to finish...") |
| 334 | b.buildingLock.RUnlock() |
| 335 | <-b.queueSignal |
| 336 | queueNoMatch = false |
| 337 | } |
| 338 | |
| 339 | // if only unknown packages are left, enable unknown buildmode |
| 340 | doneQLock.RLock() |
| 341 | b.buildingLock.RLock() |
| 342 | if up == len(queue)-(len(doneQ)+len(b.building)) { |
| 343 | // clear queueNoMatch on the transition so the next iteration |
| 344 | // gets a fair pass in unknown-mode instead of parking on a |
| 345 | // signal that may never come (e.g. b.building is empty) |
no test coverage detected