github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/zombie_collector.go (about)

     1  package instrumentation
     2  
     3  import (
     4  	"context"
     5  	"github.com/Rookout/GoSDK/pkg/augs"
     6  	"github.com/Rookout/GoSDK/pkg/locations_set"
     7  	"github.com/Rookout/GoSDK/pkg/logger"
     8  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
     9  	"github.com/Rookout/GoSDK/pkg/utils"
    10  	"sync"
    11  	"time"
    12  )
    13  
    14  type ClearBreakpointFunc func(*augs.Breakpoint) rookoutErrors.RookoutError
    15  
    16  type ZombieCollector struct {
    17  	tickInterval        time.Duration
    18  	readyTicker         *time.Ticker
    19  	signalStop          context.CancelFunc
    20  	stopCalled          context.Context
    21  	sweeperFinished     chan bool
    22  	locations           *locations_set.LocationsSet
    23  	instrumentationLock sync.Locker
    24  	clearBreakpoint     ClearBreakpointFunc
    25  	running             bool
    26  }
    27  
    28  func NewZombieCollector(collectionInterval time.Duration, locations *locations_set.LocationsSet, instrumentationLock sync.Locker, clearBreakpoint ClearBreakpointFunc) *ZombieCollector {
    29  
    30  	return &ZombieCollector{
    31  		tickInterval:        collectionInterval,
    32  		locations:           locations,
    33  		instrumentationLock: instrumentationLock,
    34  		clearBreakpoint:     clearBreakpoint,
    35  		running:             false,
    36  	}
    37  }
    38  
    39  
    40  
    41  func (z *ZombieCollector) Stop() {
    42  	if !z.running {
    43  		return
    44  	}
    45  	z.readyTicker.Stop()
    46  	z.signalStop()
    47  	<-z.sweeperFinished 
    48  	z.running = false
    49  }
    50  
    51  
    52  
    53  
    54  func (z *ZombieCollector) Start() {
    55  	if z.running {
    56  		return
    57  	}
    58  	z.stopCalled, z.signalStop = context.WithCancel(context.Background())
    59  	z.sweeperFinished = make(chan bool, 1)
    60  	z.readyTicker = time.NewTicker(z.tickInterval)
    61  	utils.CreateRetryingGoroutine(z.stopCalled, func() {
    62  		for {
    63  			select {
    64  			case <-z.stopCalled.Done():
    65  				z.sweeperFinished <- true
    66  				return
    67  			case <-z.readyTicker.C:
    68  				z.clearStaleBreakpoints()
    69  			}
    70  		}
    71  	})
    72  	z.running = true
    73  }
    74  
    75  func (z *ZombieCollector) clearStaleBreakpoints() {
    76  	z.instrumentationLock.Lock() 
    77  	defer z.instrumentationLock.Unlock()
    78  	z.locations.Lock() 
    79  	defer z.locations.Unlock()
    80  	staleBreakpoints := z.locations.GetBreakpointsToRemoveUnsafe()
    81  	for _, bp := range staleBreakpoints {
    82  		logger.Logger().Debugf("Trying to remove a stale breakpoint from %s:%d", bp.File, bp.Line)
    83  		if err := z.clearBreakpoint(bp); err != nil {
    84  			logger.Logger().WithError(err).Warningf("Failed removing stale breakpoint from %s:%d.", bp.File, bp.Line)
    85  		} else {
    86  			z.locations.RemoveBreakpointUnsafe(bp)
    87  			logger.Logger().Debugf("Removed a stale breakpoint from %s:%d", bp.File, bp.Line)
    88  		}
    89  	}
    90  }