github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/service/application_metadata_cache.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"time"
     7  
     8  	"github.com/pyroscope-io/pyroscope/pkg/model/appmetadata"
     9  )
    10  
    11  type ApplicationMetadataWriter interface {
    12  	CreateOrUpdate(ctx context.Context, application appmetadata.ApplicationMetadata) error
    13  }
    14  
    15  type ApplicationMetadataCacheService struct {
    16  	appSvc ApplicationMetadataWriter
    17  	cache  *cache
    18  }
    19  
    20  type ApplicationMetadataCacheServiceConfig struct {
    21  	Size int
    22  	TTL  time.Duration
    23  }
    24  
    25  func NewApplicationMetadataCacheService(config ApplicationMetadataCacheServiceConfig, appSvc ApplicationMetadataWriter) *ApplicationMetadataCacheService {
    26  	if config.Size <= 0 {
    27  		config.Size = 1000
    28  	}
    29  
    30  	if config.TTL <= 0 {
    31  		config.TTL = 5 * time.Minute
    32  	}
    33  
    34  	cache := newCache(config.Size, config.TTL)
    35  	return &ApplicationMetadataCacheService{appSvc: appSvc, cache: cache}
    36  }
    37  
    38  // CreateOrUpdate delegates to the underlying service in the following cases:
    39  // * item is not in the cache
    40  // * data is different from what's in the cache
    41  // Otherwise it does nothing
    42  func (svc *ApplicationMetadataCacheService) CreateOrUpdate(ctx context.Context, application appmetadata.ApplicationMetadata) error {
    43  	if cachedApp, ok := svc.cache.get(application.FQName); ok {
    44  		if !svc.isTheSame(application, cachedApp.(appmetadata.ApplicationMetadata)) {
    45  			return svc.writeToBoth(ctx, application)
    46  		}
    47  		return nil
    48  	}
    49  
    50  	// Not in cache
    51  	// Could be due to TTL
    52  	// Or could it be that's a new app
    53  	return svc.writeToBoth(ctx, application)
    54  }
    55  
    56  // writeToBoth writes to both the cache and the underlying service
    57  func (svc *ApplicationMetadataCacheService) writeToBoth(ctx context.Context, application appmetadata.ApplicationMetadata) error {
    58  	if err := svc.appSvc.CreateOrUpdate(ctx, application); err != nil {
    59  		return err
    60  	}
    61  	svc.cache.put(application.FQName, application)
    62  	return nil
    63  }
    64  
    65  // isTheSame check if 2 applications have the same data
    66  // TODO(eh-am): update to a more robust comparison function
    67  // See https://pkg.go.dev/reflect#DeepEqual for its drawbacks
    68  func (*ApplicationMetadataCacheService) isTheSame(app1 appmetadata.ApplicationMetadata, app2 appmetadata.ApplicationMetadata) bool {
    69  	return reflect.DeepEqual(app1, app2)
    70  }