danielemoraschi opened a new issue, #8788:
URL: https://github.com/apache/incubator-devlake/issues/8788

   ### Search before asking
   
   - [x] I had searched in the 
[issues](https://github.com/apache/incubator-devlake/issues?q=is%3Aissue) and 
found no similar issues.
   
   
   ### What happened
   
   When collecting data from a large repository using GitHub App 
authentication, the pipeline crashes after approximately 1 hour with the 
following panic:
   
   ```
   panic: non-200 OK status code: 401 Unauthorized body: "{
     \"message\": \"Bad credentials\",
     \"documentation_url\": \"https://docs.github.com/rest\";,
     \"status\": \"401\"
   }"
   goroutine 11186 [running]:
   
github.com/apache/incubator-devlake/helpers/pluginhelper/api.(*GraphqlAsyncClient).updateRateRemaining.func1()
        /app/helpers/pluginhelper/api/graphql_async_client.go:129
   created by 
github.com/apache/incubator-devlake/helpers/pluginhelper/api.(*GraphqlAsyncClient).updateRateRemaining
        /app/helpers/pluginhelper/api/graphql_async_client.go:117
   ```
   
   There are two independent bugs that combine to cause this:
   
   **Bug 1: Process crash on any error in the rate-limit goroutine**
   
   `graphql_async_client.go:129` calls `panic(err)` inside the background 
goroutine that periodically polls the GitHub GraphQL rate limit. Any error, 
including a transient 401, immediately kills the entire DevLake process.
   
   **Bug 2: GraphQL HTTP client holds a frozen, never-refreshed token (root 
cause)**
   
   In `backend/plugins/github_graphql/impl/impl.go` (lines 183-209), the 
GraphQL HTTP client is built with `oauth2.StaticTokenSource`:
   
   ```go
   tokens := strings.Split(connection.Token, ",")
   src := oauth2.StaticTokenSource(
       &oauth2.Token{AccessToken: tokens[0]},
   )
   httpClient := oauth2.NewClient(oauthContext, src)
   ```
   
   This freezes the token to the value at task start time. The client has no 
connection to the `TokenProvider` / `RefreshRoundTripper` machinery that 
already handles token refresh for the REST client.
   
   By contrast, `CreateApiClient` (called just above at line 173) correctly 
wires up `NewAppInstallationTokenProvider` + `RefreshRoundTripper` and 
auto-refreshes on 401. This was added in #8746. The GraphQL client was not 
updated as part of that PR and still bypasses the refresh infrastructure with 
its own isolated `oauth2` HTTP client.
   
   Since GitHub App installation tokens expire after 1 hour, any pipeline 
running longer than that will encounter 401s on all GraphQL requests. The 
rate-limit polling goroutine then hits the 401 and panics, crashing the process.
   
   Note: the documentation page at 
https://devlake.apache.org/docs/Configuration/GitHub/#github-apps-beta 
currently states "The GitHub App token expires every hour and does not 
auto-renew." This was accurate before #8746 but is now stale for the REST path. 
The GraphQL path is the remaining gap.
   
   ### What do you expect to happen
   
   - The GitHub App installation token should be transparently refreshed for 
GraphQL requests, the same way it already is for REST requests.
   - If token refresh fails or any other error occurs in the background 
rate-limit goroutine, the error should be logged and retried, not cause a 
process-wide panic.
   - Pipelines against large repositories should complete successfully without 
requiring users to fall back to Personal Access Tokens.
   
   ### How to reproduce
   
   1. Configure a GitHub connection using **GitHub App** authentication (not 
PAT).
   2. Create a blueprint targeting a large repository whose full collection 
takes more than 1 hour.
   3. Trigger the pipeline.
   4. After ~1 hour, observe the panic in the logs and the pipeline crashing.
   
   ### Anything else
   
   **Affected files:**
   
   | File | Issue |
   |---|---|
   | `backend/helpers/pluginhelper/api/graphql_async_client.go:129` | 
`panic(err)` in background goroutine crashes the process on any rate-limit poll 
error |
   | `backend/plugins/github_graphql/impl/impl.go:183-209` | 
`oauth2.StaticTokenSource` freezes the token at task start; GraphQL client is 
not wired to `TokenProvider` / `RefreshRoundTripper` |
   
   **Suggested fix:**
   
   1. In `graphql_async_client.go`, replace `panic(err)` with graceful error 
handling (log the error and reschedule the next poll) so a transient 401 does 
not crash the process.
   
   2. In `github_graphql/impl/impl.go`, instead of creating a new 
`oauth2.StaticTokenSource`-backed HTTP client, reuse `apiClient.GetClient()` -- 
the REST client's underlying `*http.Client` -- which already carries the 
`RefreshRoundTripper`. This is safe: `ApiAsyncClient` embeds `*ApiClient` which 
exposes `GetClient()`, and proxy is already configured inside 
`NewApiClientFromConnection` so the `oauthContext` proxy block becomes 
redundant. Token injection is handled by the `RefreshRoundTripper`, making the 
`oauth2` wrapper unnecessary.
   
   Related: #8746 (added token refresh for REST path)
   
   ### Version
   
   v1.0.3-beta10
   
   ### Are you willing to submit PR?
   
   - [ ] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://www.apache.org/foundation/policies/conduct)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to