@@ -2,34 +2,52 @@ import type { PythHttpClientResult } from '@pythnetwork/client/lib/PythHttpClien
2
2
import type { z } from 'zod' ;
3
3
4
4
import { Cluster , clients , priceFeedsSchema } from "../services/pyth" ;
5
- import { createChunkedCacheFetcher , fetchAllChunks } from '../utils/cache' ;
5
+ import { createChunkedCacheFetcher , fetchAllChunks , timeFunction } from '../utils/cache' ;
6
6
7
7
8
- type CachedData = {
9
- data : PythHttpClientResult ;
10
- timestamp : number ;
8
+ type CacheEntry = {
9
+ data ?: PythHttpClientResult ;
10
+ timestamp ?: number ;
11
+ promise ?: Promise < PythHttpClientResult > ;
11
12
} ;
12
13
13
- const dataCache = new Map < Cluster , CachedData > ( ) ;
14
+ const dataCache = new Map < Cluster , CacheEntry > ( ) ;
14
15
const CACHE_EXPIRY_MS = 24 * 60 * 60 ; // 1 day in seconds
15
16
16
17
const getDataCached = async ( cluster : Cluster ) => {
17
18
const now = Date . now ( ) ;
18
19
const cached = dataCache . get ( cluster ) ;
19
20
20
21
// Check if cache exists and is not expired
21
- if ( cached && ( now - cached . timestamp ) < CACHE_EXPIRY_MS * 1000 ) {
22
+ if ( cached ?. data && cached . timestamp && ( now - cached . timestamp ) < CACHE_EXPIRY_MS * 1000 ) {
22
23
return cached . data ;
23
24
}
24
25
25
- // Fetch fresh data
26
- const data = await clients [ cluster ] . getData ( ) ;
27
- dataCache . set ( cluster , { data, timestamp : now } ) ;
28
- return data ;
26
+ // Check if there's already a pending request
27
+ if ( cached ?. promise ) {
28
+ return cached . promise ;
29
+ }
30
+
31
+ // eslint-disable-next-line no-console
32
+ console . log ( 'fetching fresh FULL data' ) ;
33
+
34
+ // Create a new promise for the request
35
+ const promise = clients [ cluster ] . getData ( ) . then ( ( data ) => {
36
+ // Store the result in cache
37
+ dataCache . set ( cluster , { data, timestamp : now } ) ;
38
+ return data ;
39
+ } ) ;
40
+
41
+ // Store the promise in cache to prevent duplicate requests
42
+ dataCache . set ( cluster , { promise } ) ;
43
+
44
+ return promise ;
29
45
} ;
30
46
31
47
const fetchFeeds = createChunkedCacheFetcher ( async ( cluster : Cluster ) => {
32
48
const unfilteredData = await getDataCached ( cluster ) ;
49
+ // eslint-disable-next-line no-console
50
+ console . log ( 'fetchFeeds called' ) ;
33
51
const filteredData = unfilteredData . symbols
34
52
. filter (
35
53
( symbol ) =>
@@ -54,6 +72,8 @@ const fetchFeeds = createChunkedCacheFetcher(async (cluster: Cluster) => {
54
72
55
73
const fetchPublishers = createChunkedCacheFetcher ( async ( cluster : Cluster ) => {
56
74
const data = await getDataCached ( cluster ) ;
75
+ // eslint-disable-next-line no-console
76
+ console . log ( 'fetchPublishers called' ) ;
57
77
const result : Record < string , string [ ] > = { } ;
58
78
for ( const key of data . productPrice . keys ( ) ) {
59
79
const price = data . productPrice . get ( key ) ;
@@ -63,19 +83,25 @@ const fetchPublishers = createChunkedCacheFetcher(async (cluster: Cluster) => {
63
83
} , 'fetchPublishers' ) ;
64
84
65
85
export const getFeedsCached = async ( cluster : Cluster ) => {
66
- return fetchAllChunks < z . infer < typeof priceFeedsSchema > , [ Cluster ] > ( fetchFeeds , cluster )
86
+ return timeFunction ( async ( ) => {
87
+ return fetchAllChunks < z . infer < typeof priceFeedsSchema > , [ Cluster ] > ( fetchFeeds , cluster ) ;
88
+ } , 'getFeedsCached' ) ;
67
89
} ;
68
90
69
91
export const getPublishersForFeedCached = async ( cluster : Cluster , symbol : string ) => {
70
- const data = await fetchAllChunks < Record < string , string [ ] > , [ Cluster ] > ( fetchPublishers , cluster ) ;
92
+ const data = await timeFunction ( async ( ) => {
93
+ return fetchAllChunks < Record < string , string [ ] > , [ Cluster ] > ( fetchPublishers , cluster ) ;
94
+ } , 'getPublishersForFeedCached' ) ;
71
95
return data [ symbol ]
72
96
} ;
73
97
74
98
export const getFeedsForPublisherCached = async (
75
99
cluster : Cluster ,
76
100
publisher : string
77
101
) => {
78
- const data = await getFeedsCached ( cluster ) ;
102
+ const data = await timeFunction ( async ( ) => {
103
+ return getFeedsCached ( cluster ) ;
104
+ } , 'getFeedsForPublisherCached' ) ;
79
105
return priceFeedsSchema . parse (
80
106
data . filter ( ( { price } ) =>
81
107
price . priceComponents . some (
0 commit comments