Skip to content

Commit

Permalink
Merge pull request #134 from game-node-app/dev
Browse files Browse the repository at this point in the history
Manually handling of game-statistics cache
  • Loading branch information
Lamarcke authored Dec 15, 2024
2 parents 1ee5c4c + 66ed399 commit 1f36c74
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 29 deletions.
79 changes: 52 additions & 27 deletions src/statistics/game-statistics.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from "@nestjs/common";
import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { GameStatistics } from "./entity/game-statistics.entity";
import { Repository } from "typeorm";
Expand All @@ -11,6 +11,7 @@ import {
} from "./statistics-queue/statistics-queue.types";
import {
StatisticsActionType,
StatisticsPeriod,
StatisticsPeriodToMinusDays,
StatisticsSourceType,
} from "./statistics.constants";
Expand All @@ -21,12 +22,14 @@ import { FindStatisticsTrendingGamesDto } from "./dto/find-statistics-trending-g
import { getPreviousDate } from "./statistics.utils";
import { hours } from "@nestjs/throttler";
import { GameRepositoryService } from "../game/game-repository/game-repository.service";
import { GameFilterService } from "../game/game-filter/game-filter.service";
import { Cache } from "@nestjs/cache-manager";
import { MATURE_THEME_ID } from "../game/game-filter/game-filter.constants";
import isEmptyObject from "../utils/isEmptyObject";

@Injectable()
export class GameStatisticsService implements StatisticsService {
private logger = new Logger(GameStatisticsService.name);

constructor(
@InjectRepository(GameStatistics)
private readonly gameStatisticsRepository: Repository<GameStatistics>,
Expand All @@ -35,9 +38,27 @@ export class GameStatisticsService implements StatisticsService {
@InjectRepository(UserView)
private readonly userViewRepository: Repository<UserView>,
private readonly gameRepositoryService: GameRepositoryService,
private readonly gameFilterService: GameFilterService,
private readonly cacheManager: Cache,
) {}

private getCachedStatistics(period: StatisticsPeriod) {
return this.cacheManager.get<GameStatistics[]>(
`trending-games-statistics-${period}`,
);
}

private setCachedStatistics(
period: StatisticsPeriod,
data: GameStatistics[],
) {
this.cacheManager
.set(`trending-games-statistics-${period}`, data, hours(24))
.then()
.catch((err) => {
this.logger.error(err);
});
}

/**
* Creates a new GameStatistics. <br>
* Returns previous one if it already exists.
Expand Down Expand Up @@ -165,32 +186,36 @@ export class GameStatisticsService implements StatisticsService {
const minusDays = StatisticsPeriodToMinusDays[period];
const viewsStartDate = getPreviousDate(minusDays);

const queryBuilder =
this.gameStatisticsRepository.createQueryBuilder("s");

/**
* Made with query builder, so we can further optimize the query
*/
const query = queryBuilder
.select()
.leftJoin(UserView, `uv`, `uv.gameStatisticsId = s.id`)
.where(`(uv.createdAt >= :uvDate OR s.viewsCount = 0)`, {
uvDate: viewsStartDate,
})
// Excludes games with mature theme
.andWhere(
`NOT EXISTS (SELECT 1 FROM game_themes_game_theme AS gtgt WHERE gtgt.gameId = s.gameId
let statistics = await this.getCachedStatistics(period);

if (statistics == undefined) {
const queryBuilder =
this.gameStatisticsRepository.createQueryBuilder("s");

/**
* Made with query builder, so we can further optimize the query
*/
const query = queryBuilder
.select()
.leftJoin(UserView, `uv`, `uv.gameStatisticsId = s.id`)
.where(`(uv.createdAt >= :uvDate OR s.viewsCount = 0)`, {
uvDate: viewsStartDate,
})
// Excludes games with mature theme
.andWhere(
`NOT EXISTS (SELECT 1 FROM game_themes_game_theme AS gtgt WHERE gtgt.gameId = s.gameId
AND gtgt.gameThemeId = :excludedThemeId)`,
{
excludedThemeId: MATURE_THEME_ID,
},
)
.addOrderBy(`s.viewsCount`, `DESC`)
.skip(0)
.take(fixedStatisticsLimit)
.cache(`trending-games-statistics-${period}`, hours(24));
{
excludedThemeId: MATURE_THEME_ID,
},
)
.addOrderBy(`s.viewsCount`, `DESC`)
.skip(0)
.take(fixedStatisticsLimit);

const statistics = await query.getMany();
statistics = await query.getMany();
this.setCachedStatistics(period, statistics);
}

// This greatly improves performance when no filtering is actually being done.
if (criteria == undefined || isEmptyObject(criteria)) {
Expand Down
11 changes: 9 additions & 2 deletions src/sync/steam/steam-sync.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,18 @@ export class SteamSyncService {
language: "english",
});

const sortedGames = games.toSorted((a, b) => {
const timestampA = a.lastPlayedTimestamp ?? 0;
const timestampB = b.lastPlayedTimestamp ?? 0;

return timestampB - timestampA;
});

this.cacheManager
.set(`steam-sync-games-${steamUserId}`, games, minutes(10))
.set(`steam-sync-games-${steamUserId}`, sortedGames, minutes(10))
.then()
.catch();

return games;
return sortedGames;
}
}

0 comments on commit 1f36c74

Please sign in to comment.