From d0cea55f2dd980764b25d29b652a645e5c554e65 Mon Sep 17 00:00:00 2001 From: ftocal <46001274+ftocal@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:00:29 -0300 Subject: [PATCH] Add cache to dashboard endpoints (#441) * Add cache to dashboard endpoints * Code review updates --- api/handlers/transactions/service.go | 47 +++++++++++++++++++++++----- api/internal/config/config.go | 28 +++++++++++++---- api/main.go | 2 +- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/api/handlers/transactions/service.go b/api/handlers/transactions/service.go index 6f20c661..1479c265 100644 --- a/api/handlers/transactions/service.go +++ b/api/handlers/transactions/service.go @@ -19,37 +19,68 @@ import ( type Service struct { repo *Repository cache cache.Cache + expiration time.Duration supportedChainIDs map[vaa.ChainID]string logger *zap.Logger } +const ( + lastTxsKey = "wormscan:last-txs" + scorecardsKey = "wormscan:scorecards" + topAssetsByVolumeKey = "wormscan:top-assets-by-volume" + topChainPairsByNumTransfersKey = "wormscan:top-chain-pairs-by-num-transfers" + chainActivityKey = "wormscan:chain-activity" +) + // NewService create a new Service. -func NewService(repo *Repository, cache cache.Cache, logger *zap.Logger) *Service { +func NewService(repo *Repository, cache cache.Cache, expiration time.Duration, logger *zap.Logger) *Service { supportedChainIDs := domain.GetSupportedChainIDs() - return &Service{repo: repo, supportedChainIDs: supportedChainIDs, cache: cache, logger: logger.With(zap.String("module", "TransactionService"))} + return &Service{repo: repo, supportedChainIDs: supportedChainIDs, + cache: cache, expiration: expiration, logger: logger.With(zap.String("module", "TransactionService"))} } // GetTransactionCount get the last transactions. func (s *Service) GetTransactionCount(ctx context.Context, q *TransactionCountQuery) ([]TransactionCountResult, error) { - return s.repo.GetTransactionCount(ctx, q) + key := fmt.Sprintf("%s:%s:%s:%v", lastTxsKey, q.TimeSpan, q.SampleRate, q.CumulativeSum) + return cacheable.GetOrLoad(ctx, s.logger, s.cache, s.expiration, key, + func() ([]TransactionCountResult, error) { + return s.repo.GetTransactionCount(ctx, q) + }) } func (s *Service) GetScorecards(ctx context.Context) (*Scorecards, error) { - return s.repo.GetScorecards(ctx) + return cacheable.GetOrLoad(ctx, s.logger, s.cache, s.expiration, scorecardsKey, + func() (*Scorecards, error) { + return s.repo.GetScorecards(ctx) + }) } func (s *Service) GetTopAssets(ctx context.Context, timeSpan *TopStatisticsTimeSpan) ([]AssetDTO, error) { - return s.repo.GetTopAssets(ctx, timeSpan) + key := topAssetsByVolumeKey + if timeSpan != nil { + key = fmt.Sprintf("%s:%s", key, *timeSpan) + } + return cacheable.GetOrLoad(ctx, s.logger, s.cache, s.expiration, key, + func() ([]AssetDTO, error) { + return s.repo.GetTopAssets(ctx, timeSpan) + }) } func (s *Service) GetTopChainPairs(ctx context.Context, timeSpan *TopStatisticsTimeSpan) ([]ChainPairDTO, error) { - return s.repo.GetTopChainPairs(ctx, timeSpan) + key := topChainPairsByNumTransfersKey + if timeSpan != nil { + key = fmt.Sprintf("%s:%s", key, *timeSpan) + } + return cacheable.GetOrLoad(ctx, s.logger, s.cache, s.expiration, key, + func() ([]ChainPairDTO, error) { + return s.repo.GetTopChainPairs(ctx, timeSpan) + }) } // GetChainActivity get chain activity. func (s *Service) GetChainActivity(ctx context.Context, q *ChainActivityQuery) ([]ChainActivityResult, error) { - key := fmt.Sprintf("wormscan:chain-activity:%s:%v:%s", q.TimeSpan, q.IsNotional, strings.Join(q.GetAppIDs(), ",")) - return cacheable.GetOrLoad(ctx, s.logger, s.cache, 5*time.Minute, key, + key := fmt.Sprintf("%s:%s:%v:%s", chainActivityKey, q.TimeSpan, q.IsNotional, strings.Join(q.GetAppIDs(), ",")) + return cacheable.GetOrLoad(ctx, s.logger, s.cache, s.expiration, key, func() ([]ChainActivityResult, error) { return s.repo.FindChainActivity(ctx, q) }) diff --git a/api/internal/config/config.go b/api/internal/config/config.go index c3832aef..13562634 100644 --- a/api/internal/config/config.go +++ b/api/internal/config/config.go @@ -32,11 +32,12 @@ type AppConfig struct { Name string } Cache struct { - URL string - Channel string - TvlKey string - TvlExpiration int - Enabled bool + URL string + Channel string + TvlKey string + TvlExpiration int + Enabled bool + MetricExpiration int } PORT int LogLevel string @@ -65,6 +66,21 @@ func (cfg *AppConfig) GetLogLevel() (ipfslog.LogLevel, error) { return ipfslog.LevelFromString(cfg.LogLevel) } +func defaulConfig() *AppConfig { + return &AppConfig{ + Cache: struct { + URL string + Channel string + TvlKey string + TvlExpiration int + Enabled bool + MetricExpiration int + }{ + MetricExpiration: 10, + }, + } +} + func init() { viper.SetDefault("port", 8000) viper.SetDefault("loglevel", "INFO") @@ -74,7 +90,7 @@ func init() { viper.SetDefault("RateLimit_Enabled", true) // Consider environment variables in unmarshall doesn't work unless doing this: https://github.com/spf13/viper/issues/188#issuecomment-1168898503 - b, err := json.Marshal(AppConfig{}) + b, err := json.Marshal(defaulConfig()) if err != nil { panic(err) } diff --git a/api/main.go b/api/main.go index fa4959fa..167484ef 100644 --- a/api/main.go +++ b/api/main.go @@ -149,7 +149,7 @@ func main() { governorService := governor.NewService(governorRepo, rootLogger) infrastructureService := infrastructure.NewService(infrastructureRepo, rootLogger) heartbeatsService := heartbeats.NewService(heartbeatsRepo, rootLogger) - transactionsService := transactions.NewService(transactionsRepo, cache, rootLogger) + transactionsService := transactions.NewService(transactionsRepo, cache, time.Duration(cfg.Cache.MetricExpiration)*time.Second, rootLogger) // Set up a custom error handler response.SetEnableStackTrace(*cfg)