Browse Source

Fix portfolio snapshot cache write and initialization retry limit

pull/7517/head
Thomas Kaul 4 weeks ago
parent
commit
727373bcb6
  1. 12
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  2. 2
      apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
  3. 14
      apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock.ts

12
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -65,6 +65,8 @@ import { isNumber, sortBy, sum, uniqBy } from 'lodash';
export abstract class PortfolioCalculator { export abstract class PortfolioCalculator {
protected static readonly ENABLE_LOGGING = false; protected static readonly ENABLE_LOGGING = false;
private static readonly MAX_INITIALIZATION_ATTEMPTS = 3;
protected readonly logger = new Logger(PortfolioCalculator.name); protected readonly logger = new Logger(PortfolioCalculator.name);
protected accountBalanceItems: HistoricalDataItem[]; protected accountBalanceItems: HistoricalDataItem[];
@ -1124,7 +1126,7 @@ export abstract class PortfolioCalculator {
} }
@LogPerformance @LogPerformance
private async initialize() { private async initialize(attempt = 1) {
const startTimeTotal = performance.now(); const startTimeTotal = performance.now();
let cachedPortfolioSnapshot: PortfolioSnapshot; let cachedPortfolioSnapshot: PortfolioSnapshot;
@ -1205,7 +1207,13 @@ export abstract class PortfolioCalculator {
await job.finished(); await job.finished();
} }
await this.initialize(); if (attempt >= PortfolioCalculator.MAX_INITIALIZATION_ATTEMPTS) {
throw new Error(
`Portfolio snapshot of user '${this.userId}' could not be computed after ${attempt} attempts`
);
}
await this.initialize(attempt + 1);
} }
} }
} }

2
apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts

@ -87,7 +87,7 @@ export class PortfolioSnapshotProcessor {
: 0 : 0
); );
this.redisCacheService.set( await this.redisCacheService.set(
this.redisCacheService.getPortfolioSnapshotKey({ this.redisCacheService.getPortfolioSnapshotKey({
filters: job.data.filters, filters: job.data.filters,
userId: job.data.userId userId: job.data.userId

14
apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock.ts

@ -1,4 +1,8 @@
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface';
import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
import type { Job, JobId, JobOptions } from 'bull'; import type { Job, JobId, JobOptions } from 'bull';
import ms from 'ms';
import { setTimeout } from 'timers/promises'; import { setTimeout } from 'timers/promises';
import { PortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface'; import { PortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface';
@ -15,7 +19,15 @@ export const PortfolioSnapshotServiceMock = {
finished: async () => { finished: async () => {
await setTimeout(100); await setTimeout(100);
return Promise.resolve(); // Mimic the processor which caches the computed portfolio snapshot
// under the job id
await RedisCacheServiceMock.set(
opts?.jobId as string,
JSON.stringify({
expiration: Date.now() + ms('1 minute'),
portfolioSnapshot: {}
} as unknown as PortfolioSnapshotValue)
);
} }
}; };

Loading…
Cancel
Save