From 939eaaeddf98bfc3fbf425051b981fee0fee5058 Mon Sep 17 00:00:00 2001 From: mohamed-sameh-albaz <136837275+mohamed-sameh-albaz@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:22:48 +0200 Subject: [PATCH] fix(trends): categorize caching --- src/post/services/hashtag-trends.service.ts | 29 ++++++++++--- .../services/personalized-trends.service.ts | 6 +-- src/post/services/post.service.ts | 41 ++++++++++++------- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/post/services/hashtag-trends.service.ts b/src/post/services/hashtag-trends.service.ts index bead0e1..bf13751 100644 --- a/src/post/services/hashtag-trends.service.ts +++ b/src/post/services/hashtag-trends.service.ts @@ -180,7 +180,14 @@ export class HashtagTrendService { if (trending.length === 0) { this.logger.warn(`No trending data in Redis for ${category}, falling back to DB`); - return await this.getTrendingFromDB(limit, category); + const dbResults = await this.getTrendingFromDB(limit, category); + + if (dbResults.length > 0) { + await this.redisService.setJSON(cacheKey, dbResults, this.CACHE_TTL); + this.logger.debug(`Cached ${dbResults.length} DB results for ${category}`); + } + + return dbResults; } this.failureCount = 0; @@ -326,7 +333,6 @@ export class HashtagTrendService { return trends.map((trend) => ({ tag: `#${trend.hashtag.tag}`, totalPosts: trend.post_count_7d, - score: trend.trending_score, })); } catch (error) { this.logger.error('Failed to get trending from DB:', error); @@ -404,16 +410,29 @@ export class HashtagTrendService { } private async determineCategories(event: PostCreatedEvent): Promise { - const categories: Set = new Set([TrendCategory.GENERAL]); + const categories: Set = new Set(); + + categories.add(TrendCategory.GENERAL); if (event.interestSlug) { for (const [category, slugs] of Object.entries(CATEGORY_TO_INTERESTS)) { - if (slugs.includes(event.interestSlug)) { + if (category === TrendCategory.GENERAL || category === TrendCategory.PERSONALIZED) { + continue; + } + if (slugs.length > 0 && slugs.includes(event.interestSlug)) { categories.add(category as TrendCategory); + this.logger.debug( + `Post ${event.postId} with interest '${event.interestSlug}' mapped to category '${category}'` + ); } } } - return Array.from(categories); + const result = Array.from(categories); + this.logger.debug( + `Post ${event.postId} will be tracked in categories: ${result.join(', ')}` + ); + + return result; } } diff --git a/src/post/services/personalized-trends.service.ts b/src/post/services/personalized-trends.service.ts index 91fe2e7..c41ab30 100644 --- a/src/post/services/personalized-trends.service.ts +++ b/src/post/services/personalized-trends.service.ts @@ -41,7 +41,7 @@ export class PersonalizedTrendsService { async getPersonalizedTrending( userId: number, limit: number = 10, - ): Promise> { + ): Promise> { const cacheKey = `personalized:trending:${userId}:${limit}`; const cached = await this.redisService.getJSON(cacheKey); if (cached && cached.length > 0) { @@ -53,6 +53,7 @@ export class PersonalizedTrendsService { const userInterests = await this.usersService.getUserInterests(userId); const interestSlugs = userInterests.map((ui) => ui.slug); const categories = this.mapInterestsToCategories(interestSlugs); + if (categories.length === 0) { this.logger.debug(`User ${userId} has no interests, falling back to GENERAL`); return await this.getTrendingForCategory(TrendCategory.GENERAL, limit); @@ -71,7 +72,6 @@ export class PersonalizedTrendsService { this.logger.warn(`No personalized trends for user ${userId}, using GENERAL`); return await this.getTrendingForCategory(TrendCategory.GENERAL, limit); } - const results = await Promise.all( combinedTrends.map(async (trend) => { let metadata = await this.redisTrendingService.getHashtagMetadata( @@ -103,8 +103,6 @@ export class PersonalizedTrendsService { return { tag: `#${metadata.tag}`, totalPosts: counts.count7d, - score: trend.combinedScore, - categories: trend.categories, }; }), ); diff --git a/src/post/services/post.service.ts b/src/post/services/post.service.ts index b5b2809..8520db4 100644 --- a/src/post/services/post.service.ts +++ b/src/post/services/post.service.ts @@ -580,21 +580,32 @@ export class PostService { // Emit post.created event for real-time hashtag tracking if (hashtagIds.length > 0) { - let interestSlug: string | undefined; - if (post.interest_id) { - const interest = await this.prismaService.interest.findUnique({ - where: { id: post.interest_id }, - select: { slug: true }, - }); - interestSlug = interest?.slug; - } - this.eventEmitter.emit('post.created', { - postId: post.id, - userId: post.user_id, - hashtagIds, - interestSlug, - timestamp: post.created_at.getTime(), - }); + setTimeout(async () => { + try { + let interestSlug: string | undefined; + const updatedPost = await this.prismaService.post.findUnique({ + where: { id: post.id }, + select: { interest_id: true }, + }); + + if (updatedPost?.interest_id) { + const interest = await this.prismaService.interest.findUnique({ + where: { id: updatedPost.interest_id }, + select: { slug: true }, + }); + interestSlug = interest?.slug; + } + this.eventEmitter.emit('post.created', { + postId: post.id, + userId: post.user_id, + hashtagIds, + interestSlug, + timestamp: post.created_at.getTime(), + }); + } catch (error) { + console.error('Failed to emit post.created event:', error); + } + }, 1500); } // Update parent post stats cache if this is a reply or quote