Feature/improve portfolio snapshot caching (#3717)
* Improve portfolio snapshot caching * Update changelog
This commit is contained in:
parent
c6f804f68c
commit
71a568264d
@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
|
||||
- Reworked the portfolio calculator
|
||||
- Improved the caching of the portfolio snapshot in the portfolio calculator by returning cached data and recalculating in the background when it expires
|
||||
- Exposed the log levels as an environment variable (`LOG_LEVELS`)
|
||||
- Exposed the maximum of chart data items as an environment variable (`MAX_CHART_ITEMS`)
|
||||
- Changed the data format of the environment variable `CACHE_QUOTES_TTL` from seconds to milliseconds
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
|
||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface';
|
||||
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface';
|
||||
import { TransactionPointSymbol } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point-symbol.interface';
|
||||
import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface';
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
@ -32,6 +33,7 @@ import { Logger } from '@nestjs/common';
|
||||
import { Big } from 'big.js';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import {
|
||||
addMilliseconds,
|
||||
differenceInDays,
|
||||
eachDayOfInterval,
|
||||
endOfDay,
|
||||
@ -863,6 +865,29 @@ export abstract class PortfolioCalculator {
|
||||
return chartDateMap;
|
||||
}
|
||||
|
||||
private async computeAndCacheSnapshot() {
|
||||
const snapshot = await this.computeSnapshot();
|
||||
|
||||
const expiration = addMilliseconds(
|
||||
new Date(),
|
||||
this.configurationService.get('CACHE_QUOTES_TTL')
|
||||
);
|
||||
|
||||
this.redisCacheService.set(
|
||||
this.redisCacheService.getPortfolioSnapshotKey({
|
||||
filters: this.filters,
|
||||
userId: this.userId
|
||||
}),
|
||||
JSON.stringify(<PortfolioSnapshotValue>(<unknown>{
|
||||
expiration: expiration.getTime(),
|
||||
portfolioSnapshot: snapshot
|
||||
})),
|
||||
0
|
||||
);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@LogPerformance
|
||||
private computeTransactionPoints() {
|
||||
this.transactionPoints = [];
|
||||
@ -1006,19 +1031,33 @@ export abstract class PortfolioCalculator {
|
||||
private async initialize() {
|
||||
const startTimeTotal = performance.now();
|
||||
|
||||
const cachedSnapshot = await this.redisCacheService.get(
|
||||
this.redisCacheService.getPortfolioSnapshotKey({
|
||||
filters: this.filters,
|
||||
userId: this.userId
|
||||
})
|
||||
);
|
||||
let cachedPortfolioSnapshot: PortfolioSnapshot;
|
||||
let isCachedPortfolioSnapshotExpired = false;
|
||||
|
||||
if (cachedSnapshot) {
|
||||
this.snapshot = plainToClass(
|
||||
PortfolioSnapshot,
|
||||
JSON.parse(cachedSnapshot)
|
||||
try {
|
||||
const cachedPortfolioSnapshotValue = await this.redisCacheService.get(
|
||||
this.redisCacheService.getPortfolioSnapshotKey({
|
||||
filters: this.filters,
|
||||
userId: this.userId
|
||||
})
|
||||
);
|
||||
|
||||
const { expiration, portfolioSnapshot }: PortfolioSnapshotValue =
|
||||
JSON.parse(cachedPortfolioSnapshotValue);
|
||||
|
||||
cachedPortfolioSnapshot = plainToClass(
|
||||
PortfolioSnapshot,
|
||||
portfolioSnapshot
|
||||
);
|
||||
|
||||
if (isAfter(new Date(), new Date(expiration))) {
|
||||
isCachedPortfolioSnapshotExpired = true;
|
||||
}
|
||||
} catch {}
|
||||
|
||||
if (cachedPortfolioSnapshot) {
|
||||
this.snapshot = cachedPortfolioSnapshot;
|
||||
|
||||
Logger.debug(
|
||||
`Fetched portfolio snapshot from cache in ${(
|
||||
(performance.now() - startTimeTotal) /
|
||||
@ -1026,17 +1065,14 @@ export abstract class PortfolioCalculator {
|
||||
).toFixed(3)} seconds`,
|
||||
'PortfolioCalculator'
|
||||
);
|
||||
} else {
|
||||
this.snapshot = await this.computeSnapshot();
|
||||
|
||||
this.redisCacheService.set(
|
||||
this.redisCacheService.getPortfolioSnapshotKey({
|
||||
filters: this.filters,
|
||||
userId: this.userId
|
||||
}),
|
||||
JSON.stringify(this.snapshot),
|
||||
this.configurationService.get('CACHE_QUOTES_TTL')
|
||||
);
|
||||
if (isCachedPortfolioSnapshotExpired) {
|
||||
// Compute in the background
|
||||
this.computeAndCacheSnapshot();
|
||||
}
|
||||
} else {
|
||||
// Wait for computation
|
||||
this.snapshot = await this.computeAndCacheSnapshot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
export interface PortfolioSnapshotValue {
|
||||
expiration: number;
|
||||
portfolioSnapshot: string;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user