Implement asynchronous AI recommendation cache refresh in company service
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
- Introduced `refreshAIRecommendationsCacheAsync` method to refresh AI recommendations in the background, improving responsiveness by serving the previous cache until the refresh completes. - Updated `StartAIOnboarding` to call the new asynchronous cache refresh method instead of invalidating the cache directly. - Added logging for cache refresh operations, including success and error handling, to enhance observability. This update enhances the AI recommendation caching mechanism, providing a smoother onboarding experience and reducing latency in recommendation retrieval.
This commit is contained in:
@@ -85,7 +85,8 @@ func (s *companyService) StartAIOnboarding(ctx context.Context, companyID string
|
||||
return nil, fmt.Errorf("failed to start AI onboarding: %w", err)
|
||||
}
|
||||
|
||||
s.invalidateAIRecommendationCache(ctx, companyID)
|
||||
// Prefetch recommendations in the background; keep serving the previous cache until refresh completes.
|
||||
s.refreshAIRecommendationsCacheAsync(companyID)
|
||||
|
||||
return &OnboardingResponse{Status: result.Status}, nil
|
||||
}
|
||||
@@ -143,6 +144,48 @@ func (s *companyService) GetAIRecommendations(ctx context.Context, companyID str
|
||||
return nil, errors.New("company not found")
|
||||
}
|
||||
|
||||
return s.fetchAndCacheAIRecommendations(ctx, companyID)
|
||||
}
|
||||
|
||||
func (s *companyService) refreshAIRecommendationsCacheAsync(companyID string) {
|
||||
if s.aiRecommendationClient == nil {
|
||||
return
|
||||
}
|
||||
|
||||
companyID = strings.TrimSpace(companyID)
|
||||
if companyID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
ctx := context.Background()
|
||||
s.logger.Info("Refreshing AI recommendation cache in background", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
})
|
||||
|
||||
if _, err := s.repository.GetByID(ctx, companyID); err != nil {
|
||||
s.logger.Error("Failed to load company for AI recommendation refresh", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := s.fetchAndCacheAIRecommendations(ctx, companyID); err != nil {
|
||||
s.logger.Error("Failed to refresh AI recommendation cache", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Info("AI recommendation cache refreshed", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *companyService) fetchAndCacheAIRecommendations(ctx context.Context, companyID string) ([]RecommendedTenderResponse, error) {
|
||||
s.logger.Info("Fetching AI tender recommendations", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
})
|
||||
@@ -228,19 +271,6 @@ func (s *companyService) cacheAIRecommendations(ctx context.Context, companyID s
|
||||
}
|
||||
}
|
||||
|
||||
func (s *companyService) invalidateAIRecommendationCache(ctx context.Context, companyID string) {
|
||||
if s.redisClient == nil || s.recommendationCacheTTL <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.redisClient.Del(ctx, aiRecommendationCacheKey(companyID)); err != nil {
|
||||
s.logger.Warn("Failed to invalidate AI recommendation cache", map[string]interface{}{
|
||||
"company_id": companyID,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *companyService) buildOnboardingDocuments(fileIDs []string) (string, error) {
|
||||
if len(fileIDs) == 0 {
|
||||
return "[]", nil
|
||||
|
||||
Reference in New Issue
Block a user