From 862772a2e7be4309230b8bd3be85ed47b4bf5ffa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:56:10 +0200 Subject: [PATCH] Improve market data gathering robustness --- .../market-data/market-data.service.ts | 74 ++++++++++--------- libs/common/src/lib/config.ts | 1 + 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/apps/api/src/services/market-data/market-data.service.ts b/apps/api/src/services/market-data/market-data.service.ts index 27c741055..086434724 100644 --- a/apps/api/src/services/market-data/market-data.service.ts +++ b/apps/api/src/services/market-data/market-data.service.ts @@ -1,6 +1,7 @@ import { DateQuery } from '@ghostfolio/api/app/portfolio/interfaces/date-query.interface'; import { DataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_TIMEOUT } from '@ghostfolio/common/config'; import { UpdateMarketDataDto } from '@ghostfolio/common/dtos'; import { resetHours } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; @@ -155,49 +156,52 @@ export class MarketDataService { dataSource, symbol }: AssetProfileIdentifier & { data: Prisma.MarketDataUpdateInput[] }) { - await this.prismaService.$transaction(async (prisma) => { - if (data.length > 0) { - let minTime = Infinity; - let maxTime = -Infinity; + await this.prismaService.$transaction( + async (prisma) => { + if (data.length > 0) { + let minTime = Infinity; + let maxTime = -Infinity; - for (const { date } of data) { - const time = (date as Date).getTime(); + for (const { date } of data) { + const time = (date as Date).getTime(); - if (time < minTime) { - minTime = time; - } + if (time < minTime) { + minTime = time; + } - if (time > maxTime) { - maxTime = time; + if (time > maxTime) { + maxTime = time; + } } - } - const minDate = new Date(minTime); - const maxDate = new Date(maxTime); + const minDate = new Date(minTime); + const maxDate = new Date(maxTime); - await prisma.marketData.deleteMany({ - where: { - dataSource, - symbol, - date: { - gte: minDate, - lte: maxDate + await prisma.marketData.deleteMany({ + where: { + dataSource, + symbol, + date: { + gte: minDate, + lte: maxDate + } } - } - }); + }); - await prisma.marketData.createMany({ - data: data.map(({ date, marketPrice, state }) => ({ - dataSource, - symbol, - date: date as Date, - marketPrice: marketPrice as number, - state: state as MarketDataState - })), - skipDuplicates: true - }); - } - }); + await prisma.marketData.createMany({ + data: data.map(({ date, marketPrice, state }) => ({ + dataSource, + symbol, + date: date as Date, + marketPrice: marketPrice as number, + state: state as MarketDataState + })), + skipDuplicates: true + }); + } + }, + { timeout: DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_TIMEOUT } + ); } public async updateAssetProfileIdentifier( diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index e6d717c7b..f96a934e7 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -90,6 +90,7 @@ export const DEFAULT_PAGE_SIZE = 50; export const DEFAULT_PORT = 3333; export const DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY = 1; +export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_TIMEOUT = 60000; export const DEFAULT_PROCESSOR_GATHER_STATISTICS_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000;