|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
|
|
|
|
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
|
|
|
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
|
|
|
|
|
import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface';
|
|
|
|
@ -27,7 +28,8 @@ export class DataProviderService {
|
|
|
|
|
private readonly dataProviderInterfaces: DataProviderInterface[],
|
|
|
|
|
private readonly marketDataService: MarketDataService,
|
|
|
|
|
private readonly prismaService: PrismaService,
|
|
|
|
|
private readonly propertyService: PropertyService
|
|
|
|
|
private readonly propertyService: PropertyService,
|
|
|
|
|
private readonly redisCacheService: RedisCacheService
|
|
|
|
|
) {
|
|
|
|
|
this.initialize();
|
|
|
|
|
}
|
|
|
|
@ -235,9 +237,43 @@ export class DataProviderService {
|
|
|
|
|
} = {};
|
|
|
|
|
const startTimeTotal = performance.now();
|
|
|
|
|
|
|
|
|
|
const itemsGroupedByDataSource = groupBy(items, (item) => item.dataSource);
|
|
|
|
|
// Get items from cache
|
|
|
|
|
const itemsToFetch: IDataGatheringItem[] = [];
|
|
|
|
|
|
|
|
|
|
const promises = [];
|
|
|
|
|
for (const { dataSource, symbol } of items) {
|
|
|
|
|
const quoteString = await this.redisCacheService.get(
|
|
|
|
|
this.redisCacheService.getQuoteKey({ dataSource, symbol })
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (quoteString) {
|
|
|
|
|
try {
|
|
|
|
|
const cachedDataProviderResponse = JSON.parse(quoteString);
|
|
|
|
|
response[symbol] = cachedDataProviderResponse;
|
|
|
|
|
} catch {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!quoteString) {
|
|
|
|
|
itemsToFetch.push({ dataSource, symbol });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const numberOfItemsInCache = Object.keys(response)?.length;
|
|
|
|
|
|
|
|
|
|
if (numberOfItemsInCache) {
|
|
|
|
|
Logger.debug(
|
|
|
|
|
`Fetched ${numberOfItemsInCache} quote${
|
|
|
|
|
numberOfItemsInCache > 1 ? 's' : ''
|
|
|
|
|
} from cache in ${((performance.now() - startTimeTotal) / 1000).toFixed(
|
|
|
|
|
3
|
|
|
|
|
)} seconds`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const itemsGroupedByDataSource = groupBy(itemsToFetch, ({ dataSource }) => {
|
|
|
|
|
return dataSource;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const promises: Promise<any>[] = [];
|
|
|
|
|
|
|
|
|
|
for (const [dataSource, dataGatheringItems] of Object.entries(
|
|
|
|
|
itemsGroupedByDataSource
|
|
|
|
@ -271,6 +307,15 @@ export class DataProviderService {
|
|
|
|
|
result
|
|
|
|
|
)) {
|
|
|
|
|
response[symbol] = dataProviderResponse;
|
|
|
|
|
|
|
|
|
|
this.redisCacheService.set(
|
|
|
|
|
this.redisCacheService.getQuoteKey({
|
|
|
|
|
dataSource: DataSource[dataSource],
|
|
|
|
|
symbol
|
|
|
|
|
}),
|
|
|
|
|
JSON.stringify(dataProviderResponse),
|
|
|
|
|
this.configurationService.get('CACHE_QUOTES_TTL')
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger.debug(
|
|
|
|
@ -283,7 +328,7 @@ export class DataProviderService {
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await this.marketDataService.updateMany({
|
|
|
|
|
this.marketDataService.updateMany({
|
|
|
|
|
data: Object.keys(response)
|
|
|
|
|
.filter((symbol) => {
|
|
|
|
|
return (
|
|
|
|
|