Skip to content

Commit 7e06906

Browse files
authored
Merge pull request #5829 from EdgeApp/matthew/pair-cache
Optimize exchange rate asset pair cache handling
2 parents fece724 + d35d3b7 commit 7e06906

File tree

1 file changed

+154
-94
lines changed

1 file changed

+154
-94
lines changed

src/actions/ExchangeRateActions.ts

Lines changed: 154 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,23 @@ async function loadExchangeRateCache(): Promise<ExchangeRateCacheFile> {
140140
const { cryptoPairs, fiatPairs, rates } = asExchangeRateCacheFile(json)
141141

142142
// Keep un-expired asset pairs:
143+
const cryptoPairsMap = new Map<string, CryptoFiatPair>()
143144
for (const pair of cryptoPairs) {
144145
if (pair.expiration < now) continue
145-
out.cryptoPairs.push(pair)
146+
const tokenIdStr =
147+
pair.asset.tokenId != null ? `_${pair.asset.tokenId}` : ''
148+
const key = `${pair.asset.pluginId}${tokenIdStr}_${pair.targetFiat}`
149+
cryptoPairsMap.set(key, { ...pair, isoDate: undefined })
146150
}
151+
out.cryptoPairs = Array.from(cryptoPairsMap.values())
152+
153+
const fiatPairsMap = new Map<string, FiatFiatPair>()
147154
for (const pair of fiatPairs) {
148155
if (pair.expiration < now) continue
149-
out.fiatPairs.push(pair)
156+
const key = `${pair.fiatCode}_${pair.targetFiat}`
157+
fiatPairsMap.set(key, { ...pair, isoDate: undefined })
150158
}
159+
out.fiatPairs = Array.from(fiatPairsMap.values())
151160

152161
// Keep un-expired rates:
153162
for (const [pluginId, tokenObj] of Object.entries(rates.crypto)) {
@@ -309,112 +318,163 @@ async function fetchExchangeRates(
309318
}
310319

311320
const requests = convertToRatesParams(cryptoPairMap, fiatPairMap)
312-
for (const query of requests) {
313-
for (let attempt = 0; attempt < 5; ++attempt) {
314-
const options = {
315-
method: 'POST',
316-
headers: { 'Content-Type': 'application/json' },
317-
body: JSON.stringify(query)
318-
}
319-
try {
320-
const response = await fetchRates('v3/rates', options)
321-
if (response.ok) {
322-
const json = await response.json()
323-
const cleanedRates = asRatesParams(json)
324-
const targetFiat = fixFiatCurrencyCode(cleanedRates.targetFiat)
325-
326-
for (const cryptoRate of cleanedRates.crypto) {
327-
const { asset, isoDate, rate } = cryptoRate
328-
if (rate == null) continue
329-
330-
const { pluginId, tokenId } = asset
331-
const safeTokenId = tokenId ?? ''
332-
333-
rates.crypto[pluginId] ??= {}
334-
rates.crypto[pluginId][safeTokenId] ??= {}
335-
rates.crypto[pluginId][safeTokenId][targetFiat] ??= {
336-
current: 0,
337-
yesterday: 0,
338-
yesterdayTimestamp: 0,
339-
expiration: 0
340-
}
321+
const promises = requests.map(async query => {
322+
const options = {
323+
method: 'POST',
324+
headers: { 'Content-Type': 'application/json' },
325+
body: JSON.stringify(query)
326+
}
327+
try {
328+
const response = await fetchRates('v3/rates', options)
329+
if (response.ok) {
330+
const json = await response.json()
331+
const cleanedRates = asRatesParams(json)
332+
const targetFiat = fixFiatCurrencyCode(cleanedRates.targetFiat)
333+
334+
for (const cryptoRate of cleanedRates.crypto) {
335+
const { asset, isoDate, rate } = cryptoRate
336+
if (rate == null) continue
337+
338+
const { pluginId, tokenId } = asset
339+
const safeTokenId = tokenId ?? ''
340+
341+
rates.crypto[pluginId] ??= {}
342+
rates.crypto[pluginId][safeTokenId] ??= {}
343+
rates.crypto[pluginId][safeTokenId][targetFiat] ??= {
344+
current: 0,
345+
yesterday: 0,
346+
yesterdayTimestamp: 0,
347+
expiration: 0
348+
}
341349

342-
const rateObj = rates.crypto[pluginId][safeTokenId][targetFiat]
343-
344-
const isHistorical =
345-
isoDate != null && isoDate.getTime() < now - ONE_HOUR
346-
if (isHistorical) {
347-
const dateTimestamp = isoDate.getTime()
348-
const yesterdayTargetTimestamp = Date.parse(yesterday)
349-
const yesterdayRateTimestamp = rateObj.yesterdayTimestamp
350-
351-
// update yesterday rate if we find one closer than we have
352-
if (
353-
Math.abs(yesterdayTargetTimestamp - dateTimestamp) <
354-
Math.abs(yesterdayTargetTimestamp - yesterdayRateTimestamp)
355-
) {
356-
rates.crypto[pluginId][safeTokenId][
357-
targetFiat
358-
].yesterdayTimestamp = yesterdayTimestamp
359-
rateObj.yesterday = rate
360-
}
361-
} else {
362-
rateObj.current = rate
350+
const rateObj = rates.crypto[pluginId][safeTokenId][targetFiat]
351+
352+
const isHistorical =
353+
isoDate != null && isoDate.getTime() < now - ONE_HOUR
354+
if (isHistorical) {
355+
const dateTimestamp = isoDate.getTime()
356+
const yesterdayTargetTimestamp = Date.parse(yesterday)
357+
const yesterdayRateTimestamp = rateObj.yesterdayTimestamp
358+
359+
// update yesterday rate if we find one closer than we have
360+
if (
361+
Math.abs(yesterdayTargetTimestamp - dateTimestamp) <
362+
Math.abs(yesterdayTargetTimestamp - yesterdayRateTimestamp)
363+
) {
364+
rates.crypto[pluginId][safeTokenId][
365+
targetFiat
366+
].yesterdayTimestamp = yesterdayTimestamp
367+
rateObj.yesterday = rate
363368
}
369+
} else {
370+
rateObj.current = rate
371+
}
364372

365-
rateObj.expiration = rateExpiration
373+
rateObj.expiration = rateExpiration
374+
}
375+
for (const fiatRate of cleanedRates.fiat) {
376+
const { isoDate, rate } = fiatRate
377+
const fiatCode = fixFiatCurrencyCode(fiatRate.fiatCode)
378+
if (rate == null) continue
379+
380+
rates.fiat[fiatCode] ??= {}
381+
rates.fiat[fiatCode][targetFiat] ??= {
382+
current: 0,
383+
yesterday: 0,
384+
yesterdayTimestamp: 0,
385+
expiration: 0
366386
}
367-
for (const fiatRate of cleanedRates.fiat) {
368-
const { isoDate, rate } = fiatRate
369-
const fiatCode = fixFiatCurrencyCode(fiatRate.fiatCode)
370-
if (rate == null) continue
371-
372-
rates.fiat[fiatCode] ??= {}
373-
rates.fiat[fiatCode][targetFiat] ??= {
374-
current: 0,
375-
yesterday: 0,
376-
yesterdayTimestamp: 0,
377-
expiration: 0
378-
}
379-
const rateObj = rates.fiat[fiatCode][targetFiat]
380-
381-
const isHistorical =
382-
isoDate != null && isoDate.getTime() < now - ONE_HOUR
383-
if (isHistorical) {
384-
const dateTimestamp = isoDate.getTime()
385-
const yesterdayTargetTimestamp = Date.parse(yesterday)
386-
const yesterdayRateTimestamp = rateObj.yesterdayTimestamp
387-
388-
// update yesterday rate if we find one closer than we have
389-
if (
390-
Math.abs(yesterdayTargetTimestamp - dateTimestamp) <
391-
Math.abs(yesterdayTargetTimestamp - yesterdayRateTimestamp)
392-
) {
393-
rates.fiat[fiatCode][targetFiat].yesterdayTimestamp =
394-
yesterdayTimestamp
395-
rateObj.yesterday = rate
396-
}
397-
} else {
398-
rateObj.current = rate
387+
const rateObj = rates.fiat[fiatCode][targetFiat]
388+
389+
const isHistorical =
390+
isoDate != null && isoDate.getTime() < now - ONE_HOUR
391+
if (isHistorical) {
392+
const dateTimestamp = isoDate.getTime()
393+
const yesterdayTargetTimestamp = Date.parse(yesterday)
394+
const yesterdayRateTimestamp = rateObj.yesterdayTimestamp
395+
396+
// update yesterday rate if we find one closer than we have
397+
if (
398+
Math.abs(yesterdayTargetTimestamp - dateTimestamp) <
399+
Math.abs(yesterdayTargetTimestamp - yesterdayRateTimestamp)
400+
) {
401+
rates.fiat[fiatCode][targetFiat].yesterdayTimestamp =
402+
yesterdayTimestamp
403+
rateObj.yesterday = rate
399404
}
400-
401-
rateObj.expiration = rateExpiration
405+
} else {
406+
rateObj.current = rate
402407
}
403-
break
408+
409+
rateObj.expiration = rateExpiration
404410
}
405-
} catch (error: unknown) {
406-
console.log(
407-
`buildExchangeRates error querying rates server ${String(error)}`
411+
}
412+
} catch (error: unknown) {
413+
console.log(
414+
`buildExchangeRates error querying rates server ${String(error)}`
415+
)
416+
}
417+
})
418+
await Promise.allSettled(promises)
419+
420+
// Merge successful rate responses into the pair cache
421+
const cryptoPairCache = [...(exchangeRateCache?.cryptoPairs ?? [])]
422+
const fiatPairCache = [...(exchangeRateCache?.fiatPairs ?? [])]
423+
for (const [pluginId, tokenObj] of Object.entries(rates.crypto)) {
424+
for (const [tokenId, rateObj] of Object.entries(tokenObj)) {
425+
for (const targetFiat of Object.keys(rateObj)) {
426+
const edgeTokenId = tokenId === '' ? null : tokenId
427+
const cryptoPairIndex = cryptoPairCache.findIndex(
428+
pair =>
429+
pair.asset.pluginId === pluginId &&
430+
pair.asset.tokenId === edgeTokenId &&
431+
pair.targetFiat === targetFiat
408432
)
433+
if (cryptoPairIndex === -1) {
434+
cryptoPairCache.push({
435+
asset: { pluginId, tokenId: edgeTokenId },
436+
targetFiat,
437+
isoDate: undefined,
438+
expiration: pairExpiration
439+
})
440+
} else {
441+
cryptoPairCache[cryptoPairIndex] = {
442+
asset: { pluginId, tokenId: edgeTokenId },
443+
targetFiat,
444+
isoDate: undefined,
445+
expiration: pairExpiration
446+
}
447+
}
448+
}
449+
}
450+
}
451+
for (const [fiatCode, fiatObj] of Object.entries(rates.fiat)) {
452+
for (const targetFiat of Object.keys(fiatObj)) {
453+
const fiatPairIndex = fiatPairCache.findIndex(
454+
pair => pair.fiatCode === fiatCode && pair.targetFiat === targetFiat
455+
)
456+
if (fiatPairIndex === -1) {
457+
fiatPairCache.push({
458+
fiatCode,
459+
targetFiat,
460+
isoDate: undefined,
461+
expiration: pairExpiration
462+
})
463+
} else {
464+
fiatPairCache[fiatPairIndex] = {
465+
fiatCode,
466+
targetFiat,
467+
isoDate: undefined,
468+
expiration: pairExpiration
469+
}
409470
}
410471
}
411472
}
412-
413473
// Update the in-memory cache:
414474
exchangeRateCache = {
415475
rates,
416-
cryptoPairs: Array.from(cryptoPairMap.values()),
417-
fiatPairs: Array.from(fiatPairMap.values())
476+
cryptoPairs: cryptoPairCache,
477+
fiatPairs: fiatPairCache
418478
}
419479

420480
// Write the cache to disk:

0 commit comments

Comments
 (0)