feat: improve listens report response time

Reduce response time for larger intervals (e.g. all time) from 9 seconds
to 150ms in my tests.
This commit is contained in:
Julian Tölle 2023-09-16 23:14:35 +02:00
parent 26087e4e6d
commit 89440daf7b
2 changed files with 19 additions and 13 deletions

View file

@ -77,7 +77,7 @@ export const ReportListens: React.FC = () => {
{isLoading && <Spinner className="m-8" />}
{!reportHasItems && !isLoading && (
<div>
<p>Report is emtpy! :(</p>
<p>Report is empty! :(</p>
</div>
)}
{reportHasItems && (
@ -128,7 +128,7 @@ const ReportGraph: React.FC<{
<AreaChart
data={dataLocal}
margin={{
left: -20,
left: -5,
}}
>
<defs>

View file

@ -10,7 +10,6 @@ import {
isSameMonth,
isSameWeek,
isSameYear,
min,
parseJSON,
startOfDay,
sub,
@ -73,7 +72,13 @@ export class ReportsService {
async getListens(options: GetListenReportDto): Promise<ListenReportDto> {
const { timeFrame, time: timePreset } = options;
const listens = await this.getListensQueryFromOptions(options).getMany();
const results = await this.getListensQueryFromOptions(options)
.select(`count(*) as "listenCount"`)
.addSelect(`date_trunc(:timeFrame, "playedAt") as date`)
.groupBy("date")
.orderBy("date")
.setParameter("timeFrame", timeFrame)
.getRawMany<{ listenCount: string; date: Date }>();
const interval = this.getIntervalFromPreset(timePreset);
const { eachOfInterval, isSame } = timeframeToDateFns[timeFrame];
@ -81,18 +86,19 @@ export class ReportsService {
// Optimize performance for ALL_TIME by skipping eachOfInterval for time
// between 1970 and first listen
if (timePreset.timePreset === TimePreset.ALL_TIME) {
let firstListen = min(listens.map(({ playedAt }) => playedAt));
interval.start = startOfDay(firstListen);
interval.start = startOfDay(results[0].date);
}
// TODO: This code blocks the eventloop for multiple seconds if running for
// a large interval and with many listens. Refactor to make this more
// efficient or make pauses for event loop.
const reportItems = eachOfInterval(interval).map((date) => {
const count = listens.filter((listen) =>
isSame(date, listen.playedAt),
).length;
return { date: formatISO(date), count };
const dayResults = results.find((listen) => isSame(date, listen.date));
return {
date: formatISO(date),
count:
dayResults && dayResults.listenCount
? Number.parseInt(dayResults.listenCount)
: 0,
};
});
return { items: reportItems };