refactor: parallelize some async code to try to make website faster

This commit is contained in:
Valentin Kaelin 2023-09-26 23:10:54 +02:00
parent e0dfeeb0fc
commit bd21281787
No known key found for this signature in database
GPG key ID: B389A4E3DFF8E414
3 changed files with 54 additions and 57 deletions

View file

@ -33,7 +33,6 @@ export default class SummonersController {
public async basic({ request, response }: HttpContextContract) { public async basic({ request, response }: HttpContextContract) {
console.time('BASIC_REQUEST') console.time('BASIC_REQUEST')
const { summoner, region } = await request.validate(SummonerBasicValidator) const { summoner, region } = await request.validate(SummonerBasicValidator)
const finalJSON: any = {}
try { try {
const account = await SummonerService.getAccount(summoner, region) const account = await SummonerService.getAccount(summoner, region)
@ -41,16 +40,20 @@ export default class SummonersController {
if (!account) { if (!account) {
return response.json(null) return response.json(null)
} }
finalJSON.account = account
// Summoner in DB // Summoner in DB
const summonerDB = await Summoner.firstOrCreate({ puuid: account.puuid }) const summonerDB = await Summoner.firstOrCreate({ puuid: account.puuid })
// Summoner names const [names, seasons, gamemodes, current, ranked, recentActivity] = await Promise.all([
finalJSON.account.names = await SummonerService.getAllSummonerNames(account, summonerDB) await SummonerService.getAllSummonerNames(account, summonerDB),
this.getSeasons(account.puuid),
// Only last 100 matchIds in matchlist MatchRepository.gamemodes(account.puuid),
await MatchService.updateMatchList(account.puuid, region, MatchListMode.LIGHT) Jax.Spectator.summonerID(account.id, region),
SummonerService.getRanked(account.id, region),
MatchRepository.recentActivity(account.puuid),
// Only last 100 matchIds in matchlist
await MatchService.updateMatchList(account.puuid, region, MatchListMode.LIGHT),
])
// Add job in 1sec to load entire matchlist in DB (in background) // Add job in 1sec to load entire matchlist in DB (in background)
const matchListMode = summonerDB.$isLocal ? MatchListMode.FIRSTIME : MatchListMode.UPDATE const matchListMode = summonerDB.$isLocal ? MatchListMode.FIRSTIME : MatchListMode.UPDATE
@ -60,33 +63,23 @@ export default class SummonersController {
1000 1000
) )
// All seasons the summoner has played console.timeEnd('BASIC_REQUEST')
finalJSON.seasons = await this.getSeasons(account.puuid) return response.json({
account: {
// All gamemodes the summoner has played ...account,
finalJSON.gamemodes = (await MatchRepository.gamemodes(account.puuid)).map((g) => g.gamemode) names,
},
// CURRENT GAME seasons, // All seasons the summoner has played
console.time('playing') gamemodes: gamemodes.map((g) => g.gamemode), // All gamemodes the summoner has played
finalJSON.current = await Jax.Spectator.summonerID(account.id, region) playing: !!current,
finalJSON.playing = !!finalJSON.current ranked,
console.timeEnd('playing') recentActivity,
})
// RANKED STATS
console.time('ranked')
finalJSON.ranked = await SummonerService.getRanked(account.id, region)
console.timeEnd('ranked')
// RECENT ACTIVITY
finalJSON.recentActivity = await StatsService.getRecentActivity(account.puuid)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
console.timeEnd('BASIC_REQUEST') console.timeEnd('BASIC_REQUEST')
return response.json(null) return response.json(null)
} }
console.timeEnd('BASIC_REQUEST')
return response.json(finalJSON)
} }
/** /**

View file

@ -82,6 +82,7 @@ class MatchRepository {
} }
public async recentActivity(puuid: string) { public async recentActivity(puuid: string) {
console.time('RECENT_ACTIVITY')
const query = ` const query = `
SELECT SELECT
to_timestamp(matches.date/1000)::date as day, to_timestamp(matches.date/1000)::date as day,
@ -100,10 +101,12 @@ class MatchRepository {
day day
` `
const { rows } = await Database.rawQuery(query, { puuid }) const { rows } = await Database.rawQuery(query, { puuid })
console.timeEnd('RECENT_ACTIVITY')
return rows return rows
} }
public async globalStats(filters: SelectFilters) { public async globalStats(filters: SelectFilters) {
console.time('GLOBAL')
const query = ` const query = `
SELECT SELECT
COALESCE(SUM(match_players.kills), 0) as kills, COALESCE(SUM(match_players.kills), 0) as kills,
@ -126,10 +129,12 @@ class MatchRepository {
` `
const { rows } = await Database.rawQuery(query, filters as any) const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('GLOBAL')
return rows[0] return rows[0]
} }
public async gamemodeStats(filters: SelectFilters) { public async gamemodeStats(filters: SelectFilters) {
console.time('GAMEMODE')
const query = ` const query = `
SELECT SELECT
matches.gamemode as id, matches.gamemode as id,
@ -148,10 +153,12 @@ class MatchRepository {
` `
const { rows } = await Database.rawQuery(query, filters as any) const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('GAMEMODE')
return rows return rows
} }
public async roleStats(filters: SelectFilters) { public async roleStats(filters: SelectFilters) {
console.time('ROLE')
const query = ` const query = `
SELECT SELECT
match_players.team_position as role, match_players.team_position as role,
@ -169,10 +176,12 @@ class MatchRepository {
` `
const { rows } = await Database.rawQuery(query, filters as any) const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('ROLE')
return rows return rows
} }
public async championStats(filters: SelectFilters) { public async championStats(filters: SelectFilters) {
console.time('CHAMPION')
const query = ` const query = `
SELECT SELECT
match_players.champion_id as id, match_players.champion_id as id,
@ -196,10 +205,12 @@ class MatchRepository {
` `
const { rows } = await Database.rawQuery(query, filters as any) const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('CHAMPION')
return rows return rows
} }
public async championClassStats(filters: SelectFilters) { public async championClassStats(filters: SelectFilters) {
console.time('CHAMPION-CLASS')
const query = ` const query = `
SELECT SELECT
match_players.champion_role as id, match_players.champion_role as id,
@ -218,10 +229,12 @@ class MatchRepository {
` `
const { rows } = await Database.rawQuery(query, filters as any) const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('CHAMPION-CLASS')
return rows return rows
} }
public async mates(filters: SelectFilters) { public async mates(filters: SelectFilters) {
console.time('MATES')
const query = ` const query = `
SELECT SELECT
( (
@ -255,6 +268,7 @@ class MatchRepository {
` `
const { rows } = await Database.rawQuery(query, filters as any) const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('MATES')
// Remove the Summoner himself + unique game mates // Remove the Summoner himself + unique game mates
return rows.splice(1).filter((row) => row.count > 1) return rows.splice(1).filter((row) => row.count > 1)

View file

@ -4,24 +4,28 @@ import MatchRepository, { SelectFilters } from 'App/Repositories/MatchRepository
import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer' import BasicMatchSerializer from 'App/Serializers/BasicMatchSerializer'
class StatsService { class StatsService {
public async getRecentActivity(puuid: string) {
console.time('RecentActivity')
const recentActivity = await MatchRepository.recentActivity(puuid)
console.timeEnd('RecentActivity')
return recentActivity
}
public async getSummonerStats(puuid: string, season?: number) { public async getSummonerStats(puuid: string, season?: number) {
const filters: SelectFilters = { puuid } const filters: SelectFilters = { puuid }
if (season) filters.season = season if (season) filters.season = season
console.time('GLOBAL') const [
const globalStats = await MatchRepository.globalStats(filters) globalStats,
console.timeEnd('GLOBAL') gamemodeStats,
console.time('GAMEMODE') roleStats,
const gamemodeStats = await MatchRepository.gamemodeStats(filters) championStats,
console.timeEnd('GAMEMODE') championClassStats,
console.time('ROLE') mates,
const roleStats = await MatchRepository.roleStats(filters) recentActivity,
] = await Promise.all([
MatchRepository.globalStats(filters),
MatchRepository.gamemodeStats(filters),
MatchRepository.roleStats(filters),
MatchRepository.championStats({ ...filters, limit: 5 }),
MatchRepository.championClassStats(filters),
MatchRepository.mates(filters),
MatchRepository.recentActivity(puuid),
])
// Check if all roles are in the array // Check if all roles are in the array
const roles = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY'] const roles = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY']
for (const role of roles) { for (const role of roles) {
@ -37,26 +41,12 @@ class StatsService {
}) })
} }
} }
console.timeEnd('ROLE')
console.time('CHAMPION')
const championStats = await MatchRepository.championStats({ ...filters, limit: 5 })
for (const champ of championStats) { for (const champ of championStats) {
champ.champion = BasicMatchSerializer.getChampion(champ.id) champ.champion = BasicMatchSerializer.getChampion(champ.id)
} }
console.timeEnd('CHAMPION')
console.time('CHAMPION-CLASS')
const championClassStats = await MatchRepository.championClassStats(filters)
for (const champ of championClassStats) { for (const champ of championClassStats) {
champ.id = ChampionRoles[champ.id] champ.id = ChampionRoles[champ.id]
} }
console.timeEnd('CHAMPION-CLASS')
console.time('MATES')
const mates = await MatchRepository.mates(filters)
console.timeEnd('MATES')
console.time('RECENT_ACTIVITY')
const recentActivity = await MatchRepository.recentActivity(puuid)
console.timeEnd('RECENT_ACTIVITY')
return { return {
global: globalStats, global: globalStats,