github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/worker/volume_sweeper.go (about)

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