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) {
console.time('BASIC_REQUEST')
const { summoner, region } = await request.validate(SummonerBasicValidator)
const finalJSON: any = {}
try {
const account = await SummonerService.getAccount(summoner, region)
@ -41,16 +40,20 @@ export default class SummonersController {
if (!account) {
return response.json(null)
}
finalJSON.account = account
// Summoner in DB
const summonerDB = await Summoner.firstOrCreate({ puuid: account.puuid })
// Summoner names
finalJSON.account.names = await SummonerService.getAllSummonerNames(account, summonerDB)
// Only last 100 matchIds in matchlist
await MatchService.updateMatchList(account.puuid, region, MatchListMode.LIGHT)
const [names, seasons, gamemodes, current, ranked, recentActivity] = await Promise.all([
await SummonerService.getAllSummonerNames(account, summonerDB),
this.getSeasons(account.puuid),
MatchRepository.gamemodes(account.puuid),
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)
const matchListMode = summonerDB.$isLocal ? MatchListMode.FIRSTIME : MatchListMode.UPDATE
@ -60,33 +63,23 @@ export default class SummonersController {
1000
)
// All seasons the summoner has played
finalJSON.seasons = await this.getSeasons(account.puuid)
// All gamemodes the summoner has played
finalJSON.gamemodes = (await MatchRepository.gamemodes(account.puuid)).map((g) => g.gamemode)
// CURRENT GAME
console.time('playing')
finalJSON.current = await Jax.Spectator.summonerID(account.id, region)
finalJSON.playing = !!finalJSON.current
console.timeEnd('playing')
// 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)
console.timeEnd('BASIC_REQUEST')
return response.json({
account: {
...account,
names,
},
seasons, // All seasons the summoner has played
gamemodes: gamemodes.map((g) => g.gamemode), // All gamemodes the summoner has played
playing: !!current,
ranked,
recentActivity,
})
} catch (e) {
console.log(e)
console.timeEnd('BASIC_REQUEST')
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) {
console.time('RECENT_ACTIVITY')
const query = `
SELECT
to_timestamp(matches.date/1000)::date as day,
@ -100,10 +101,12 @@ class MatchRepository {
day
`
const { rows } = await Database.rawQuery(query, { puuid })
console.timeEnd('RECENT_ACTIVITY')
return rows
}
public async globalStats(filters: SelectFilters) {
console.time('GLOBAL')
const query = `
SELECT
COALESCE(SUM(match_players.kills), 0) as kills,
@ -126,10 +129,12 @@ class MatchRepository {
`
const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('GLOBAL')
return rows[0]
}
public async gamemodeStats(filters: SelectFilters) {
console.time('GAMEMODE')
const query = `
SELECT
matches.gamemode as id,
@ -148,10 +153,12 @@ class MatchRepository {
`
const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('GAMEMODE')
return rows
}
public async roleStats(filters: SelectFilters) {
console.time('ROLE')
const query = `
SELECT
match_players.team_position as role,
@ -169,10 +176,12 @@ class MatchRepository {
`
const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('ROLE')
return rows
}
public async championStats(filters: SelectFilters) {
console.time('CHAMPION')
const query = `
SELECT
match_players.champion_id as id,
@ -196,10 +205,12 @@ class MatchRepository {
`
const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('CHAMPION')
return rows
}
public async championClassStats(filters: SelectFilters) {
console.time('CHAMPION-CLASS')
const query = `
SELECT
match_players.champion_role as id,
@ -218,10 +229,12 @@ class MatchRepository {
`
const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('CHAMPION-CLASS')
return rows
}
public async mates(filters: SelectFilters) {
console.time('MATES')
const query = `
SELECT
(
@ -255,6 +268,7 @@ class MatchRepository {
`
const { rows } = await Database.rawQuery(query, filters as any)
console.timeEnd('MATES')
// Remove the Summoner himself + unique game mates
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'
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) {
const filters: SelectFilters = { puuid }
if (season) filters.season = season
console.time('GLOBAL')
const globalStats = await MatchRepository.globalStats(filters)
console.timeEnd('GLOBAL')
console.time('GAMEMODE')
const gamemodeStats = await MatchRepository.gamemodeStats(filters)
console.timeEnd('GAMEMODE')
console.time('ROLE')
const roleStats = await MatchRepository.roleStats(filters)
const [
globalStats,
gamemodeStats,
roleStats,
championStats,
championClassStats,
mates,
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
const roles = ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY']
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) {
champ.champion = BasicMatchSerializer.getChampion(champ.id)
}
console.timeEnd('CHAMPION')
console.time('CHAMPION-CLASS')
const championClassStats = await MatchRepository.championClassStats(filters)
for (const champ of championClassStats) {
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 {
global: globalStats,