@@ -1568,26 +1568,22 @@ func (s *Server) processRepoSample(ctx context.Context, req *RepoSampleRequest,
15681568 // Calculate since date
15691569 since := time .Now ().AddDate (0 , 0 , - req .Days )
15701570
1571- // Try cache first
1572- cacheKey := fmt .Sprintf ("repo:%s/%s:days=%d" , req .Owner , req .Repo , req .Days )
1573- prs , cached := s .cachedPRQuery (ctx , cacheKey )
1574- if cached {
1575- s .logger .InfoContext (ctx , "Using cached PR query results" ,
1576- "owner" , req .Owner , "repo" , req .Repo , "total_prs" , len (prs ))
1577- } else {
1578- // Fetch all PRs modified since the date
1579- var err error
1580- prs , err = github .FetchPRsFromRepo (ctx , req .Owner , req .Repo , since , token , nil )
1581- if err != nil {
1582- return nil , fmt .Errorf ("failed to fetch PRs: %w" , err )
1583- }
1571+ // Fetch all PRs modified since the date (cache uses query hash internally)
1572+ var err error
1573+ var queryHash string
1574+ prs , queryHash , err := github .FetchPRsFromRepo (ctx , req .Owner , req .Repo , since , token , nil )
1575+ if err != nil {
1576+ return nil , fmt .Errorf ("failed to fetch PRs: %w" , err )
1577+ }
15841578
1585- s . logger . InfoContext ( ctx , "Fetched PRs from repository" ,
1586- "owner " , req .Owner , "repo" , req .Repo , "total_prs" , len ( prs ) )
1579+ // Cache key includes query hash to invalidate when query structure changes
1580+ cacheKey := fmt . Sprintf ( "repo:%s/%s:days=%d:qh=%s " , req .Owner , req .Repo , req . Days , queryHash )
15871581
1588- // Cache query results
1589- s .cachePRQuery (ctx , cacheKey , prs )
1590- }
1582+ s .logger .InfoContext (ctx , "Fetched PRs from repository" ,
1583+ "owner" , req .Owner , "repo" , req .Repo , "total_prs" , len (prs ), "query_hash" , queryHash )
1584+
1585+ // Cache query results
1586+ s .cachePRQuery (ctx , cacheKey , prs )
15911587
15921588 if len (prs ) == 0 {
15931589 return nil , fmt .Errorf ("no PRs found in the last %d days" , req .Days )
@@ -1704,25 +1700,21 @@ func (s *Server) processOrgSample(ctx context.Context, req *OrgSampleRequest, to
17041700 // Calculate since date
17051701 since := time .Now ().AddDate (0 , 0 , - req .Days )
17061702
1707- // Try cache first
1708- cacheKey := fmt .Sprintf ("org:%s:days=%d" , req .Org , req .Days )
1709- prs , cached := s .cachedPRQuery (ctx , cacheKey )
1710- if cached {
1711- s .logger .InfoContext (ctx , "Using cached PR query results" ,
1712- "org" , req .Org , "total_prs" , len (prs ))
1713- } else {
1714- // Fetch all PRs across the org modified since the date
1715- var err error
1716- prs , err = github .FetchPRsFromOrg (ctx , req .Org , since , token , nil )
1717- if err != nil {
1718- return nil , fmt .Errorf ("failed to fetch PRs: %w" , err )
1719- }
1703+ // Fetch all PRs across the org modified since the date (cache uses query hash internally)
1704+ var err error
1705+ var queryHash string
1706+ prs , queryHash , err := github .FetchPRsFromOrg (ctx , req .Org , since , token , nil )
1707+ if err != nil {
1708+ return nil , fmt .Errorf ("failed to fetch PRs: %w" , err )
1709+ }
17201710
1721- s .logger .InfoContext (ctx , "Fetched PRs from organization" , "org" , req .Org , "total_prs" , len (prs ))
1711+ // Cache key includes query hash to invalidate when query structure changes
1712+ cacheKey := fmt .Sprintf ("org:%s:days=%d:qh=%s" , req .Org , req .Days , queryHash )
17221713
1723- // Cache query results
1724- s .cachePRQuery (ctx , cacheKey , prs )
1725- }
1714+ s .logger .InfoContext (ctx , "Fetched PRs from organization" , "org" , req .Org , "total_prs" , len (prs ), "query_hash" , queryHash )
1715+
1716+ // Cache query results
1717+ s .cachePRQuery (ctx , cacheKey , prs )
17261718
17271719 if len (prs ) == 0 {
17281720 return nil , fmt .Errorf ("no PRs found in the last %d days" , req .Days )
@@ -2131,54 +2123,53 @@ func (s *Server) processRepoSampleWithProgress(ctx context.Context, req *RepoSam
21312123 // Calculate since date
21322124 since := time .Now ().AddDate (0 , 0 , - req .Days )
21332125
2134- // Try cache first
2135- cacheKey := fmt .Sprintf ("repo:%s/%s:days=%d" , req .Owner , req .Repo , req .Days )
2136- prs , cached := s .cachedPRQuery (ctx , cacheKey )
2137- if ! cached {
2138- // Send progress update before GraphQL query
2126+ // Send progress update before GraphQL query
2127+ logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2128+ Type : "fetching" ,
2129+ PR : 0 ,
2130+ Owner : req .Owner ,
2131+ Repo : req .Repo ,
2132+ Progress : fmt .Sprintf ("Querying GitHub GraphQL API for %s/%s PRs (last %d days)..." , req .Owner , req .Repo , req .Days ),
2133+ }))
2134+
2135+ // Start keep-alive to prevent client timeout during GraphQL query
2136+ stopKeepAlive , connErr := startKeepAlive (writer )
2137+ defer close (stopKeepAlive )
2138+
2139+ // Check for connection errors in background
2140+ go func () {
2141+ if err := <- connErr ; err != nil {
2142+ s .logger .WarnContext (ctx , "Client connection lost" , errorKey , err )
2143+ }
2144+ }()
2145+
2146+ // Fetch all PRs modified since the date with progress updates
2147+ var err error
2148+ var queryHash string
2149+ progressCallback := func (queryName string , page int , prCount int ) {
21392150 logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
21402151 Type : "fetching" ,
21412152 PR : 0 ,
21422153 Owner : req .Owner ,
21432154 Repo : req .Repo ,
2144- Progress : fmt .Sprintf ("Querying GitHub GraphQL API for %s/%s PRs (last %d days )..." , req . Owner , req . Repo , req . Days ),
2155+ Progress : fmt .Sprintf ("Fetching %s PRs (page %d, %d PRs found )..." , queryName , page , prCount ),
21452156 }))
2157+ }
2158+ //nolint:contextcheck // Using background context intentionally to prevent client timeout from canceling work
2159+ prs , queryHash , err := github .FetchPRsFromRepo (workCtx , req .Owner , req .Repo , since , token , progressCallback )
2160+ if err != nil {
2161+ logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2162+ Type : "error" ,
2163+ Error : fmt .Sprintf ("Failed to fetch PRs: %v" , err ),
2164+ }))
2165+ return
2166+ }
21462167
2147- // Start keep-alive to prevent client timeout during GraphQL query
2148- stopKeepAlive , connErr := startKeepAlive (writer )
2149- defer close (stopKeepAlive )
2150-
2151- // Check for connection errors in background
2152- go func () {
2153- if err := <- connErr ; err != nil {
2154- s .logger .WarnContext (ctx , "Client connection lost" , errorKey , err )
2155- }
2156- }()
2157-
2158- // Fetch all PRs modified since the date with progress updates
2159- var err error
2160- progressCallback := func (queryName string , page int , prCount int ) {
2161- logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2162- Type : "fetching" ,
2163- PR : 0 ,
2164- Owner : req .Owner ,
2165- Repo : req .Repo ,
2166- Progress : fmt .Sprintf ("Fetching %s PRs (page %d, %d PRs found)..." , queryName , page , prCount ),
2167- }))
2168- }
2169- //nolint:contextcheck // Using background context intentionally to prevent client timeout from canceling work
2170- prs , err = github .FetchPRsFromRepo (workCtx , req .Owner , req .Repo , since , token , progressCallback )
2171- if err != nil {
2172- logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2173- Type : "error" ,
2174- Error : fmt .Sprintf ("Failed to fetch PRs: %v" , err ),
2175- }))
2176- return
2177- }
2168+ // Cache key includes query hash to invalidate when query structure changes
2169+ cacheKey := fmt .Sprintf ("repo:%s/%s:days=%d:qh=%s" , req .Owner , req .Repo , req .Days , queryHash )
21782170
2179- // Cache query results
2180- s .cachePRQuery (ctx , cacheKey , prs )
2181- }
2171+ // Cache query results
2172+ s .cachePRQuery (ctx , cacheKey , prs )
21822173
21832174 if len (prs ) == 0 {
21842175 logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
@@ -2290,52 +2281,51 @@ func (s *Server) processOrgSampleWithProgress(ctx context.Context, req *OrgSampl
22902281 // Calculate since date
22912282 since := time .Now ().AddDate (0 , 0 , - req .Days )
22922283
2293- // Try cache first
2294- cacheKey := fmt .Sprintf ("org:%s:days=%d" , req .Org , req .Days )
2295- prs , cached := s .cachedPRQuery (ctx , cacheKey )
2296- if ! cached {
2297- // Send progress update before GraphQL query
2284+ // Send progress update before GraphQL query
2285+ logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2286+ Type : "fetching" ,
2287+ PR : 0 ,
2288+ Progress : fmt .Sprintf ("Querying GitHub Search API for %s org PRs (last %d days)..." , req .Org , req .Days ),
2289+ }))
2290+
2291+ // Start keep-alive to prevent client timeout during GraphQL query
2292+ stopKeepAlive , connErr := startKeepAlive (writer )
2293+ defer close (stopKeepAlive )
2294+
2295+ // Check for connection errors in background
2296+ go func () {
2297+ if err := <- connErr ; err != nil {
2298+ s .logger .WarnContext (ctx , "Client connection lost" , errorKey , err )
2299+ }
2300+ }()
2301+
2302+ // Fetch all PRs across the org modified since the date with progress updates
2303+ var err error
2304+ var queryHash string
2305+ progressCallback := func (queryName string , page int , prCount int ) {
22982306 logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
22992307 Type : "fetching" ,
23002308 PR : 0 ,
2301- Progress : fmt .Sprintf ("Querying GitHub Search API for %s org PRs (last %d days)..." , req .Org , req .Days ),
2309+ Owner : req .Org ,
2310+ Repo : "" ,
2311+ Progress : fmt .Sprintf ("Fetching %s PRs (page %d, %d PRs found)..." , queryName , page , prCount ),
23022312 }))
2313+ }
2314+ //nolint:contextcheck // Using background context intentionally to prevent client timeout from canceling work
2315+ prs , queryHash , err := github .FetchPRsFromOrg (workCtx , req .Org , since , token , progressCallback )
2316+ if err != nil {
2317+ logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2318+ Type : "error" ,
2319+ Error : fmt .Sprintf ("Failed to fetch PRs: %v" , err ),
2320+ }))
2321+ return
2322+ }
23032323
2304- // Start keep-alive to prevent client timeout during GraphQL query
2305- stopKeepAlive , connErr := startKeepAlive (writer )
2306- defer close (stopKeepAlive )
2307-
2308- // Check for connection errors in background
2309- go func () {
2310- if err := <- connErr ; err != nil {
2311- s .logger .WarnContext (ctx , "Client connection lost" , errorKey , err )
2312- }
2313- }()
2324+ // Cache key includes query hash to invalidate when query structure changes
2325+ cacheKey := fmt .Sprintf ("org:%s:days=%d:qh=%s" , req .Org , req .Days , queryHash )
23142326
2315- // Fetch all PRs across the org modified since the date with progress updates
2316- var err error
2317- progressCallback := func (queryName string , page int , prCount int ) {
2318- logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2319- Type : "fetching" ,
2320- PR : 0 ,
2321- Owner : req .Org ,
2322- Repo : "" ,
2323- Progress : fmt .Sprintf ("Fetching %s PRs (page %d, %d PRs found)..." , queryName , page , prCount ),
2324- }))
2325- }
2326- //nolint:contextcheck // Using background context intentionally to prevent client timeout from canceling work
2327- prs , err = github .FetchPRsFromOrg (workCtx , req .Org , since , token , progressCallback )
2328- if err != nil {
2329- logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
2330- Type : "error" ,
2331- Error : fmt .Sprintf ("Failed to fetch PRs: %v" , err ),
2332- }))
2333- return
2334- }
2335-
2336- // Cache query results
2337- s .cachePRQuery (ctx , cacheKey , prs )
2338- }
2327+ // Cache query results
2328+ s .cachePRQuery (ctx , cacheKey , prs )
23392329
23402330 if len (prs ) == 0 {
23412331 logSSEError (ctx , s .logger , sendSSE (writer , ProgressUpdate {
0 commit comments