feat(cache): add read-through cache layer across all app services
Introduce a generic read-through caching infrastructure and wire it into all major tenant app services to reduce database load on hot read paths. Key changes: - Add `DeletePrefix` to Cache interface with memory (prefix scan) and Redis (SCAN + DEL) implementations - New `readthrough.go`: generic `LoadJSON` / `LoadJSONWithEmpty` helpers backed by singleflight to prevent cache stampedes; supports jittered TTL - New `cache_support.go`: centralized cache key builders and invalidation helpers for all entities (workspace, brand, prompt rules, schedule tasks, articles) - Wire optional cache into ArticleService, BrandService, WorkspaceService, PromptRuleService, ScheduleTaskService, TemplateService, MediaService, PromptGenerateService via `WithCache()` builder pattern - ScheduleDispatchWorker invalidates schedule task cache after dispatching - ArticleService gains a new `Detail` endpoint with empty-result caching - Update cmd entrypoints and transport handlers to propagate cache
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/geo-platform/tenant-api/internal/shared/auth"
|
||||
sharedcache "github.com/geo-platform/tenant-api/internal/shared/cache"
|
||||
"github.com/geo-platform/tenant-api/internal/shared/response"
|
||||
)
|
||||
|
||||
@@ -22,12 +23,18 @@ const minBrowserExtensionVersion = "0.1.0"
|
||||
type MediaService struct {
|
||||
pool *pgxpool.Pool
|
||||
logger *zap.Logger
|
||||
cache sharedcache.Cache
|
||||
}
|
||||
|
||||
func NewMediaService(pool *pgxpool.Pool, logger *zap.Logger) *MediaService {
|
||||
return &MediaService{pool: pool, logger: logger}
|
||||
}
|
||||
|
||||
func (s *MediaService) WithCache(c sharedcache.Cache) *MediaService {
|
||||
s.cache = c
|
||||
return s
|
||||
}
|
||||
|
||||
type MediaPlatformResponse struct {
|
||||
ID int64 `json:"id"`
|
||||
PlatformID string `json:"platform_id"`
|
||||
@@ -543,6 +550,7 @@ func (s *MediaService) CreatePublishBatch(ctx context.Context, articleID int64,
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return nil, response.ErrInternal(50042, "publish_batch_commit_failed", "failed to commit publish batch")
|
||||
}
|
||||
invalidateArticleCaches(ctx, s.cache, actor.TenantID, &articleID)
|
||||
|
||||
return &CreatePublishBatchResponse{
|
||||
PublishBatchID: publishBatchID,
|
||||
@@ -829,6 +837,7 @@ func (s *MediaService) HandlePublishCallback(ctx context.Context, req PluginPubl
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return nil, response.ErrInternal(50056, "publish_callback_commit_failed", "failed to commit publish callback")
|
||||
}
|
||||
invalidateArticleCaches(ctx, s.cache, session.TenantID, &articleID)
|
||||
|
||||
return &PluginPublishCallbackResponse{
|
||||
PublishRecordID: req.PublishRecordID,
|
||||
|
||||
Reference in New Issue
Block a user