feat(channel): enhance channel service with caching and repository updates
All checks were successful
Build Backend / build (push) Successful in 13m4s
Build Backend / build-docker (push) Successful in 1m22s

- Updated ChannelService to include caching for channel lists, improving performance and reducing database load.
- Introduced cache invalidation methods to ensure channel list consistency after modifications.
- Modified ChannelRepository to remove unused ListByIDs method, streamlining the repository interface.
- Updated wire generation to inject cache into ChannelService for enhanced functionality.
- Added new cache key constants for channel-related data management.
This commit is contained in:
lafay
2026-03-25 01:03:34 +08:00
parent 7c14cf5bab
commit a887e8ea23
5 changed files with 78 additions and 29 deletions

View File

@@ -1,10 +1,16 @@
package service
import (
"time"
"carrot_bbs/internal/cache"
"carrot_bbs/internal/model"
"carrot_bbs/internal/repository"
)
// 频道全量列表缓存 TTL频道变更少可较长管理端写入后会主动失效
const channelAllListCacheTTL = 10 * time.Minute
type ChannelService interface {
ListActive() ([]*model.Channel, error)
ListAll() ([]*model.Channel, error)
@@ -16,32 +22,68 @@ type ChannelService interface {
type channelServiceImpl struct {
channelRepo *repository.ChannelRepository
cache cache.Cache
}
func NewChannelService(channelRepo *repository.ChannelRepository) ChannelService {
return &channelServiceImpl{channelRepo: channelRepo}
func NewChannelService(channelRepo *repository.ChannelRepository, c cache.Cache) ChannelService {
return &channelServiceImpl{channelRepo: channelRepo, cache: c}
}
func (s *channelServiceImpl) ListActive() ([]*model.Channel, error) {
return s.channelRepo.ListActive()
func (s *channelServiceImpl) invalidateChannelListCache() {
if s.cache != nil {
cache.InvalidateChannelList(s.cache)
}
}
func (s *channelServiceImpl) ListAll() ([]*model.Channel, error) {
func (s *channelServiceImpl) listAllFromDB() ([]*model.Channel, error) {
return s.channelRepo.ListAll()
}
func (s *channelServiceImpl) MapByIDs(ids []string) (map[string]*model.Channel, error) {
list, err := s.channelRepo.ListByIDs(ids)
func (s *channelServiceImpl) ListAll() ([]*model.Channel, error) {
if s.cache == nil {
return s.listAllFromDB()
}
cs := cache.GetSettings()
return cache.GetOrLoadTyped(s.cache, cache.ChannelsAllListKey(), channelAllListCacheTTL, cs.JitterRatio, cs.NullTTL, s.listAllFromDB)
}
func (s *channelServiceImpl) ListActive() ([]*model.Channel, error) {
all, err := s.ListAll()
if err != nil {
return nil, err
}
m := make(map[string]*model.Channel, len(list))
for _, ch := range list {
if ch != nil {
m[ch.ID] = ch
out := make([]*model.Channel, 0, len(all))
for _, ch := range all {
if ch != nil && ch.IsActive {
c := *ch
out = append(out, &c)
}
}
return m, nil
return out, nil
}
// MapByIDs 始终基于全量频道列表Redis 命中则零 SQL否则一次 ListAll与 ListActive / 公开列表共用同一缓存快照。
func (s *channelServiceImpl) MapByIDs(ids []string) (map[string]*model.Channel, error) {
if len(ids) == 0 {
return nil, nil
}
all, err := s.ListAll()
if err != nil {
return nil, err
}
byID := make(map[string]*model.Channel, len(all))
for _, ch := range all {
if ch != nil {
byID[ch.ID] = ch
}
}
out := make(map[string]*model.Channel, len(ids))
for _, id := range ids {
if ch, ok := byID[id]; ok {
out[id] = ch
}
}
return out, nil
}
func (s *channelServiceImpl) Create(name, slug, description string, sortOrder int, isActive bool) (*model.Channel, error) {
@@ -55,6 +97,7 @@ func (s *channelServiceImpl) Create(name, slug, description string, sortOrder in
if err := s.channelRepo.Create(channel); err != nil {
return nil, err
}
s.invalidateChannelListCache()
return channel, nil
}
@@ -71,10 +114,16 @@ func (s *channelServiceImpl) Update(id, name, slug, description string, sortOrde
if err := s.channelRepo.Update(channel); err != nil {
return nil, err
}
s.invalidateChannelListCache()
return channel, nil
}
func (s *channelServiceImpl) Delete(id string) error {
return s.channelRepo.Delete(id)
err := s.channelRepo.Delete(id)
if err != nil {
return err
}
s.invalidateChannelListCache()
return nil
}