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]
