11const { C } = require ( '../../constants/runtime-constants' ) ;
22const redisClient = require ( '../../datasources/redis-client' ) ;
3+ const { sendWebhookMessage } = require ( '../../utils/discord' ) ;
34const Log = require ( '../../utils/logging' ) ;
45const SubgraphQueryUtil = require ( '../../utils/subgraph-query' ) ;
56const { SG_CACHE_CONFIG } = require ( './cache-config' ) ;
67const CommonSubgraphRepository = require ( './common-subgraph' ) ;
78
89// Caches past season results for configured queries, enabling retrieval of the full history to be fast
910class SubgraphCache {
11+ // Introspection is required at runtime to build the schema.
12+ // If the schema of an underlying subgraph changes, the API must be redeployed (or apollo restarted).
13+ // Therefore the schema can be cached here rather than retrieved at runtime on each request.
14+ static initialIntrospection = { } ;
15+ static introspectionDeployment = { } ;
16+
1017 static async get ( cacheQueryName , where ) {
1118 const sgName = SG_CACHE_CONFIG [ cacheQueryName ] . subgraph ;
1219
13- const introspection = await this . introspect ( sgName ) ;
20+ const introspection = this . initialIntrospection [ sgName ] ;
1421
1522 const { latest, cache } = await this . _getCachedResults ( cacheQueryName , where ) ;
1623 const freshResults = await this . _queryFreshResults ( cacheQueryName , where , latest , introspection ) ;
@@ -64,14 +71,17 @@ class SubgraphCache {
6471 }
6572
6673 if ( ! fromCache ) {
67- Log . info ( `New deployment detected; clearing subgraph cache for ${ sgName } ` ) ;
68- await this . clear ( sgName ) ;
69-
70- await redisClient . set ( `sg-deployment:${ sgName } ` , deployment ) ;
71- await redisClient . set ( `sg-introspection:${ sgName } ` , JSON . stringify ( queryInfo ) ) ;
74+ await this . _newDeploymentDetected ( sgName , deployment ) ;
7275 }
7376
74- return queryInfo ;
77+ this . introspectionDeployment [ sgName ] = deployment ;
78+ return ( this . initialIntrospection [ sgName ] = queryInfo ) ;
79+ }
80+
81+ static async _newDeploymentDetected ( sgName , deployment ) {
82+ Log . info ( `New deployment detected; clearing subgraph cache for ${ sgName } ` ) ;
83+ await this . clear ( sgName ) ;
84+ await redisClient . set ( `sg-deployment:${ sgName } ` , deployment ) ;
7585 }
7686
7787 // Recursively build a type string to use in the re-exported schema
@@ -88,7 +98,8 @@ class SubgraphCache {
8898
8999 static async _getCachedResults ( cacheQueryName , where ) {
90100 const cfg = SG_CACHE_CONFIG [ cacheQueryName ] ;
91- const cachedResults = JSON . parse ( await redisClient . get ( `sg:${ cfg . subgraph } :${ cacheQueryName } :${ where } ` ) ) ?? [ ] ;
101+ const redisResult = await redisClient . get ( `sg:${ cfg . subgraph } :${ cacheQueryName } :${ where } ` ) ;
102+ const cachedResults = JSON . parse ( redisResult ) ?? [ ] ;
92103
93104 return {
94105 latest :
@@ -101,8 +112,9 @@ class SubgraphCache {
101112
102113 static async _queryFreshResults ( cacheQueryName , where , latestValue , introspection , c = C ( ) ) {
103114 const cfg = SG_CACHE_CONFIG [ cacheQueryName ] ;
115+ const sgClient = cfg . client ( c ) ;
104116 const results = await SubgraphQueryUtil . allPaginatedSG (
105- cfg . client ( c ) ,
117+ sgClient ,
106118 `{ ${ cfg . queryName } { ${ introspection [ cacheQueryName ] . fields
107119 . filter ( ( f ) => ! cfg . omitFields ?. includes ( f . name ) )
108120 . concat ( cfg . syntheticFields ?. map ( ( f ) => ( { name : f . queryAccessor } ) ) ?? [ ] )
@@ -113,6 +125,14 @@ class SubgraphCache {
113125 { ...cfg . paginationSettings , lastValue : latestValue }
114126 ) ;
115127
128+ // If new deployment detected, clear the cache and send an alert that API might need restarting
129+ if ( sgClient . meta . deployment !== this . introspectionDeployment [ cfg . subgraph ] ) {
130+ sendWebhookMessage (
131+ `New deployment detected for ${ cfg . subgraph } , the API might need to be restarted (if the schema changed).`
132+ ) ;
133+ await this . _newDeploymentDetected ( cfg . subgraph , sgClient . meta . deployment ) ;
134+ }
135+
116136 for ( const result of results ) {
117137 for ( const syntheticField of cfg . syntheticFields ?? [ ] ) {
118138 result [ syntheticField . objectRewritePath ] = syntheticField . objectAccessor ( result ) ;
0 commit comments