github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/worker/container_sweeper.go (about) 1 package worker 2 3 import ( 4 "context" 5 "os" 6 "sync" 7 "time" 8 9 "code.cloudfoundry.org/garden" 10 "code.cloudfoundry.org/lager" 11 "code.cloudfoundry.org/lager/lagerctx" 12 "github.com/pf-qiu/concourse/v6/atc/worker/gclient" 13 ) 14 15 // ContainerSweeper is an ifrit.Runner that periodically reports and 16 // garbage-collects a worker's containers 17 type ContainerSweeper struct { 18 logger lager.Logger 19 interval time.Duration 20 tsaClient TSAClient 21 gardenClient gclient.Client 22 maxInFlight uint16 23 } 24 25 func NewContainerSweeper( 26 logger lager.Logger, 27 sweepInterval time.Duration, 28 tsaClient TSAClient, 29 gardenClient gclient.Client, 30 maxInFlight uint16, 31 ) *ContainerSweeper { 32 return &ContainerSweeper{ 33 logger: logger, 34 interval: sweepInterval, 35 tsaClient: tsaClient, 36 gardenClient: gardenClient, 37 maxInFlight: maxInFlight, 38 } 39 } 40 41 func (sweeper *ContainerSweeper) Run(signals <-chan os.Signal, ready chan<- struct{}) error { 42 timer := time.NewTicker(sweeper.interval) 43 44 close(ready) 45 46 for { 47 select { 48 case <-timer.C: 49 sweeper.sweep(sweeper.logger.Session("tick")) 50 51 case sig := <-signals: 52 sweeper.logger.Info("sweep-cancelled-by-signal", lager.Data{"signal": sig}) 53 return nil 54 } 55 } 56 } 57 58 func (sweeper *ContainerSweeper) sweep(logger lager.Logger) { 59 ctx := lagerctx.NewContext(context.Background(), logger) 60 61 containers, err := sweeper.gardenClient.Containers(garden.Properties{}) 62 if err != nil { 63 logger.Error("failed-to-list-containers", err) 64 } else { 65 handles := []string{} 66 for _, container := range containers { 67 handles = append(handles, container.Handle()) 68 } 69 70 err := sweeper.tsaClient.ReportContainers(ctx, handles) 71 if err != nil { 72 logger.Error("failed-to-report-containers", err) 73 } 74 } 75 76 containerHandles, err := sweeper.tsaClient.ContainersToDestroy(ctx) 77 if err != nil { 78 logger.Error("failed-to-get-containers-to-destroy", err) 79 } else { 80 var wg sync.WaitGroup 81 maxInFlight := make(chan int, sweeper.maxInFlight) 82 83 for _, handle := range containerHandles { 84 maxInFlight <- 1 85 wg.Add(1) 86 87 go func(handle string) { 88 err := sweeper.gardenClient.Destroy(handle) 89 if err != nil { 90 logger.WithData(lager.Data{"handle": handle}).Error("failed-to-destroy-container", err) 91 } 92 <-maxInFlight 93 wg.Done() 94 }(handle) 95 } 96 wg.Wait() 97 } 98 }