Refactor recommendation response handling and enhance enrichment logic
continuous-integration/drone/push Build is passing

- Removed the `buildRecommendedTenderResponsesParallel` method and replaced it with `buildRecommendedTenderListResponses`, simplifying the response building process.
- Introduced `enrichRecommendedTenderResponsesParallel` to handle enrichment of tender responses in parallel, improving performance.
- Updated the `Recommend` method to utilize the new enrichment logic, ensuring timely and efficient processing of recommendations.
- Cleaned up unused functions and imports in `recommendation_page_cache.go` and `recommendation_response.go`, enhancing code clarity and maintainability.

This update streamlines the recommendation response handling and improves the overall efficiency of the tender recommendation service.
This commit is contained in:
Mazyar
2026-07-08 02:27:25 +03:30
parent 784c3d6563
commit f68b6d7787
3 changed files with 91 additions and 72 deletions
+5 -68
View File
@@ -8,9 +8,6 @@ import (
"time"
"github.com/redis/go-redis/v9"
"go.mongodb.org/mongo-driver/v2/bson"
"golang.org/x/sync/errgroup"
"tm/internal/company"
"tm/pkg/response"
)
@@ -92,7 +89,7 @@ func (s *tenderService) buildRecommendedTendersPageCache(ctx context.Context, co
return nil
}
responses := s.buildRecommendedTenderResponsesParallel(ctx, items, language)
responses := s.buildRecommendedTenderListResponses(items, language)
page := cachedRecommendedTendersPage{
BuiltAt: time.Now().Unix(),
CompanyID: companyID,
@@ -204,54 +201,6 @@ func (s *tenderService) buildAllRankedRecommendations(
return out, nil
}
func (s *tenderService) buildRecommendedTenderResponsesParallel(
ctx context.Context,
items []rankedRecommendedTender,
language string,
) []TenderResponse {
if len(items) == 0 {
return nil
}
out := make([]TenderResponse, len(items))
if len(items) == 1 {
out[0] = s.buildRecommendedTenderResponse(
ctx, items[0].tender, items[0].rank, items[0].analysis, items[0].tenderRef, language,
newRecommendationTranslationCache(),
)
return out
}
translationCache := newRecommendationTranslationCache()
group, groupCtx := errgroup.WithContext(ctx)
group.SetLimit(recommendationPageCacheConcurrency)
for i := range items {
i := i
item := items[i]
group.Go(func() error {
out[i] = s.buildRecommendedTenderResponse(
groupCtx, item.tender, item.rank, item.analysis, item.tenderRef, language, translationCache,
)
return nil
})
}
if err := group.Wait(); err != nil {
s.logger.Warn("Parallel recommendation page cache build degraded to sequential", map[string]interface{}{
"error": err.Error(),
"count": len(items),
})
for i, item := range items {
out[i] = s.buildRecommendedTenderResponse(
ctx, item.tender, item.rank, item.analysis, item.tenderRef, language, translationCache,
)
}
}
return out
}
func (s *tenderService) recommendFromPageCache(
ctx context.Context,
companyID string,
@@ -292,8 +241,11 @@ func (s *tenderService) recommendFromPageCache(
end = len(filtered)
}
paged := append([]TenderResponse(nil), filtered[start:end]...)
paged = s.enrichRecommendedTenderResponsesParallel(ctx, paged, lang)
return &SearchResponse{
Tenders: append([]TenderResponse(nil), filtered[start:end]...),
Tenders: paged,
Metadata: pagination.ListMeta(total, "", end < len(filtered), start),
}, true
}
@@ -376,21 +328,6 @@ func filterCachedRecommendedTenders(
return out
}
func tenderFromRecommendationResponse(item TenderResponse) Tender {
var tender Tender
if id, err := bson.ObjectIDFromHex(strings.TrimSpace(item.ID)); err == nil {
tender.ID = id
}
tender.ContractFolderID = item.ContractFolderID
tender.NoticePublicationID = item.NoticePublicationID
tender.RelatedNoticePublicationIDs = append([]string(nil), item.RelatedNoticePublicationIDs...)
tender.Status = item.Status
tender.PublicationDate = item.PublicationDate
tender.SubmissionDeadline = item.SubmissionDeadline
tender.TenderDeadline = item.TenderDeadline
return tender
}
// RecommendedTendersPageCacheKeyPrefix is shared with company invalidation logic.
const RecommendedTendersPageCacheKeyPrefix = recommendedTendersPageCacheKeyPrefix