diff --git a/apps/api/src/events/events.module.ts b/apps/api/src/events/events.module.ts index df943a3c95..dabc3edb77 100644 --- a/apps/api/src/events/events.module.ts +++ b/apps/api/src/events/events.module.ts @@ -1,9 +1,12 @@ import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; +import { UserModule } from '@ghostfolio/api/app/user/user.module'; +import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; +import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { Module } from '@nestjs/common'; @@ -13,11 +16,14 @@ import { PortfolioChangedListener } from './portfolio-changed.listener'; @Module({ imports: [ ActivitiesModule, + ApiModule, ConfigurationModule, DataGatheringQueueModule, DataProviderModule, ExchangeRateDataModule, - RedisCacheModule + PortfolioSnapshotQueueModule, + RedisCacheModule, + UserModule ], providers: [AssetProfileChangedListener, PortfolioChangedListener] }) diff --git a/apps/api/src/events/portfolio-changed.listener.ts b/apps/api/src/events/portfolio-changed.listener.ts index 12441517b8..36a9e704a4 100644 --- a/apps/api/src/events/portfolio-changed.listener.ts +++ b/apps/api/src/events/portfolio-changed.listener.ts @@ -1,4 +1,12 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; +import { UserService } from '@ghostfolio/api/app/user/user.service'; +import { ApiService } from '@ghostfolio/api/services/api/api.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { + PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW, + PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, + PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS +} from '@ghostfolio/common/config'; import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; @@ -14,7 +22,12 @@ export class PortfolioChangedListener { private debounceTimers = new Map(); - public constructor(private readonly redisCacheService: RedisCacheService) {} + public constructor( + private readonly apiService: ApiService, + private readonly portfolioSnapshotService: PortfolioSnapshotService, + private readonly redisCacheService: RedisCacheService, + private readonly userService: UserService + ) {} @OnEvent(PortfolioChangedEvent.getName()) handlePortfolioChangedEvent(event: PortfolioChangedEvent) { @@ -39,6 +52,31 @@ export class PortfolioChangedListener { private async processPortfolioChanged({ userId }: { userId: string }) { this.logger.log(`Portfolio of user '${userId}' has changed`); - await this.redisCacheService.removePortfolioSnapshotsByUserId({ userId }); + try { + await this.redisCacheService.removePortfolioSnapshotsByUserId({ userId }); + + const user = await this.userService.user({ id: userId }); + const userSettings = user.settings.settings; + + // Recompute in the background to avoid a cold start on the next request + await this.portfolioSnapshotService.addJobToQueue({ + data: { + userId, + calculationType: userSettings.performanceCalculationType, + filters: this.apiService.buildFiltersFromUserSettings({ + userSettings + }), + userCurrency: userSettings.baseCurrency + }, + name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, + opts: { + ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, + jobId: userId, + priority: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW + } + }); + } catch (error) { + this.logger.error(error); + } } } diff --git a/apps/api/src/services/api/api.service.ts b/apps/api/src/services/api/api.service.ts index 052119246d..11074870ef 100644 --- a/apps/api/src/services/api/api.service.ts +++ b/apps/api/src/services/api/api.service.ts @@ -1,4 +1,4 @@ -import { Filter } from '@ghostfolio/common/interfaces'; +import { Filter, UserSettings } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; @@ -89,4 +89,18 @@ export class ApiService { return filters; } + + public buildFiltersFromUserSettings({ + userSettings + }: { + userSettings: UserSettings; + }): Filter[] { + return this.buildFiltersFromQueryParams({ + filterByAccounts: userSettings?.['filters.accounts']?.[0], + filterByAssetClasses: userSettings?.['filters.assetClasses']?.[0], + filterByDataSource: userSettings?.['filters.dataSource'], + filterBySymbol: userSettings?.['filters.symbol'], + filterByTags: userSettings?.['filters.tags']?.[0] + }); + } }