Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Refresh app tokens #201

Closed

Conversation

sicarul
Copy link
Contributor

@sicarul sicarul commented May 9, 2023

When running long initial syncs using Github app private keys, the tokens expire in 1 hour, which makes the process fail after this timespan. This PR separates the app tokens into a new function refresh_app_token that can get called again in get_next_auth_token, i've tested it for my use case and it no longer fails after 1 hour.

@ericboucher
Copy link
Contributor

Thanks @sicarul for your PR. I'll have a look and test it. In the meantime, could you make sure mypy and other tests are passing?

@sicarul
Copy link
Contributor Author

sicarul commented May 11, 2023

I've fixed the mypy error, it seems it doesn't like me defining the type of the variable on init for some reason

@sonarcloud
Copy link

sonarcloud bot commented May 16, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@sicarul sicarul requested a review from laurentS May 17, 2023 14:04
# Update last refresh timestamp
self.last_private_key_token_refresh = datetime.now()

return TokenRateLimit(app_token, rate_limit_buffer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a change in behavior as it returns only this token now.

Copy link
Contributor Author

@sicarul sicarul Jun 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refresh_app_token is a new function i created, can you explain how is this a change in behavior? Maybe it's confusing because of how the diff got the change?

prepare_tokens still returns all tokens as it did, it just doesn't do the private key part anymore, which is now handled by this function when all other tokens are used up.

        if self.active_token is None:
            self.active_token = self.refresh_app_token()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! I think the fact that this token is now handled outside of "prepare_tokens" is a bit confusing.

Copy link
Contributor

@ericboucher ericboucher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sicarul for opening this PR and sorry it took so long to get back to you.

The logic looks great overall. However, I think it would make more sense to add the new timestamp check within TokenRateLimit or something along these lines. This way, you will be able to keep running the tap with multiple token types if needed and leverage the existing calls to "is_valid" and other rate-limiting checks.

Let me know what you think!

@sicarul
Copy link
Contributor Author

sicarul commented Jun 7, 2023

Hey @ericboucher i don't understand how would the timestamp check work in that class, it does not handle any kind of token refresh and it's used for all types of tokens, by putting the logic there it seems i would be generating a spaghetti of code to me, but maybe i'm just not understanding how do you want me to change this.

@ericboucher
Copy link
Contributor

@sicarul I was thinking that you could either augment the TokenRateLimit class, or use it as a subclass of a new AppTokenRateLimit class which would:

  • add the necessary info to refresh the token (github_app_id, github_private_key, github_installation_id)
  • override the is_valid function to handle the refresh if necessary

I believe this would make the code a bit cleaner and keep the token logic in one place. If you prefer your current approach, make sure to add sufficient comments in the code to guide users/readers and make it clear how things are split between normal tokens and app tokens

@laurentS
Copy link
Contributor

laurentS commented Jun 9, 2023

If I may chime in, I did find it a bit difficult to follow the overall logic (some high level comments would help a lot). Am I getting this right?

  • the tap first tries to load GITHUB_TOKEN... tokens passed as env vars, then loads a private key based one, only if there are no other tokens (during init). So you can't cumulate API tokens+private key anymore (self.token_map never gets the app token now)?
  • then as it uses tokens, we call get_next_auth_token if we run out of quota (which we know from getting an error from the server), to rotate the token (but this excludes the private key based one)
  • then when getting auth_headers we would rotate the private key based token if that's what we're using.

If the above is correct:

  • I find it confusing that there is a non-obvious side effect in auth_headers (of refreshing the token)
  • I think it's a regression if we can't use both types of tokens together anymore (we might want to cumulate limits from multiple accounts).

@sicarul
Copy link
Contributor Author

sicarul commented Jun 9, 2023

Got it, i'm going on a vacation tomorrow until July but when i come back i can check this feedback and apply it to get a better version out if it's fine with you all!

@laurentS sorry if it's not clear, but this version will still use both types of tokens as i implemented it.

@sicarul
Copy link
Contributor Author

sicarul commented Aug 15, 2024

Closing since this is being fixed in the new PR: #289

@sicarul sicarul closed this Aug 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants