Skip to content

Commit

Permalink
implement simple cache for news (#459)
Browse files Browse the repository at this point in the history
* implement simple cache for news

* improve cache key method name

* use lru for cache

* cleanup

* remove previous cache
  • Loading branch information
joschahenningsen authored Oct 30, 2024
1 parent 645a161 commit a8a948a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 25 deletions.
78 changes: 53 additions & 25 deletions server/backend/news.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ import (
"context"
"errors"
"fmt"

"gorm.io/gorm"

"google.golang.org/protobuf/types/known/timestamppb"
"time"

pb "github.com/TUM-Dev/Campus-Backend/server/api/tumdev"
"github.com/TUM-Dev/Campus-Backend/server/model"
"github.com/hashicorp/golang-lru/v2/expirable"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
"gorm.io/gorm"
)

var newsSourceCache = expirable.NewLRU[string, []model.NewsSource](1, nil, time.Hour*6)
var newsCache = expirable.NewLRU[string, []model.News](1024, nil, time.Minute*30)

func (s *CampusServer) ListNewsSources(ctx context.Context, _ *pb.ListNewsSourcesRequest) (*pb.ListNewsSourcesReply, error) {
if err := s.checkDevice(ctx); err != nil {
return nil, err
}

var sources []model.NewsSource
if err := s.db.WithContext(ctx).
Joins("File").
Find(&sources).Error; err != nil {
log.WithError(err).Error("could not find news_sources")
sources, err := s.getNewsSources(ctx)
if err != nil {
return nil, status.Error(codes.Internal, "could not ListNewsSources")
}

Expand All @@ -40,27 +40,27 @@ func (s *CampusServer) ListNewsSources(ctx context.Context, _ *pb.ListNewsSource
return &pb.ListNewsSourcesReply{Sources: resp}, nil
}

const CacheKeyAllNewsSources = "all_news_sources"

func (s *CampusServer) getNewsSources(ctx context.Context) ([]model.NewsSource, error) {
if newsSources, ok := newsSourceCache.Get(CacheKeyAllNewsSources); ok {
return newsSources, nil
}
var sources []model.NewsSource
if err := s.db.WithContext(ctx).Joins("File").Find(&sources).Error; err != nil {
return nil, err
}
newsSourceCache.Add(CacheKeyAllNewsSources, sources)
return sources, nil
}

func (s *CampusServer) ListNews(ctx context.Context, req *pb.ListNewsRequest) (*pb.ListNewsReply, error) {
if err := s.checkDevice(ctx); err != nil {
return nil, err
}

var newsEntries []model.News
tx := s.db.WithContext(ctx).
Joins("File").
Joins("NewsSource").
Joins("NewsSource.File")
if req.NewsSource != 0 {
tx = tx.Where("src = ?", req.NewsSource)
}
if req.OldestDateAt.GetSeconds() != 0 || req.OldestDateAt.GetNanos() != 0 {
tx = tx.Where("date > ?", req.OldestDateAt.AsTime())
}
if req.LastNewsId != 0 {
tx = tx.Where("news > ?", req.LastNewsId)
}
if err := tx.Find(&newsEntries).Error; err != nil {
log.WithError(err).Error("could not find news item")
var newsEntries, err = s.getNews(ctx, req.NewsSource, req.LastNewsId, req.OldestDateAt.AsTime())
if err != nil {
return nil, status.Error(codes.Internal, "could not ListNews")
}

Expand All @@ -86,6 +86,34 @@ func (s *CampusServer) ListNews(ctx context.Context, req *pb.ListNewsRequest) (*
return &pb.ListNewsReply{News: resp}, nil
}

func (s *CampusServer) getNews(ctx context.Context, sourceID int32, lastNewsID int32, oldestDateAt time.Time) ([]model.News, error) {
cacheKey := fmt.Sprintf("%d_%d_%d", sourceID, oldestDateAt.Second(), lastNewsID)

if news, ok := newsCache.Get(cacheKey); ok {
return news, nil
}

var news []model.News
tx := s.db.WithContext(ctx).
Joins("File").
Joins("NewsSource").
Joins("NewsSource.File")
if sourceID != 0 {
tx = tx.Where("src = ?", sourceID)
}
if oldestDateAt.Second() != 0 || oldestDateAt.Nanosecond() != 0 {
tx = tx.Where("date > ?", oldestDateAt)
}
if lastNewsID != 0 {
tx = tx.Where("news > ?", lastNewsID)
}
if err := tx.Find(&news).Error; err != nil {
return nil, err
}
newsCache.Add(cacheKey, news)
return news, nil
}

func (s *CampusServer) ListNewsAlerts(ctx context.Context, req *pb.ListNewsAlertsRequest) (*pb.ListNewsAlertsReply, error) {
if err := s.checkDevice(ctx); err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions server/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
Expand Down
2 changes: 2 additions & 0 deletions server/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjw
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/guregu/null v4.0.0+incompatible h1:4zw0ckM7ECd6FNNddc3Fu4aty9nTlpkkzH7dPn4/4Gw=
github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down

0 comments on commit a8a948a

Please sign in to comment.