-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Skip GitHub fast path when rate-limited #13033
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
Changes from 14 commits
0b9e8d1
3d0ea05
e11c0ea
7dd16fd
6eeb463
1ff93df
8ff2112
eab2d32
066169d
c14c21b
a2a9dac
5e04f88
1fb7bca
29ce14c
7a7fd11
f3f8355
0431722
67f9a65
dc85d68
a093666
912dbaa
872d6ee
8875411
e9b0a90
3a55cf6
ab45228
9d94d9b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| use std::sync::LazyLock; | ||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||
|
|
||
| /// A global state on whether we are being rate-limited by GitHub's REST API. | ||
| /// If we are, avoid "fast-path" attempts. | ||
| pub(crate) static GITHUB_RATE_LIMIT_STATUS: LazyLock<GitHubRateLimitStatus> = | ||
| LazyLock::new(GitHubRateLimitStatus::default); | ||
oconnor663 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// GitHub REST API rate limit status tracker. | ||
| /// | ||
| /// ## Assumptions | ||
| /// | ||
| /// The rate limit timeout duration is much longer than the runtime of a `uv` command. | ||
| /// And so we do not need to invalidate this state based on `x-ratelimit-reset`. | ||
| #[derive(Debug, Default)] | ||
| pub(crate) struct GitHubRateLimitStatus(AtomicBool); | ||
|
|
||
| impl GitHubRateLimitStatus { | ||
| pub(crate) fn activate(&self) { | ||
| self.0.store(true, Ordering::SeqCst); | ||
oconnor663 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| pub(crate) fn is_active(&self) -> bool { | ||
| self.0.load(Ordering::SeqCst) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -667,6 +667,10 @@ impl EnvVars { | |
| #[attr_hidden] | ||
| pub const UV_TEST_INDEX_URL: &'static str = "UV_TEST_INDEX_URL"; | ||
|
|
||
| /// Used to set the GitHub fast-path url for tests. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should document what shape of URL is expected, is there something that GitHub considers as API root that users could exchange?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This env var's intended use is to mock the GitHub API root during tests. It's not meant for users to override, and is hidden from user-facing docs with I can rename this to Please let me know what you think. |
||
| #[attr_hidden] | ||
| pub const UV_GITHUB_FAST_PATH_URL: &'static str = "UV_GITHUB_FAST_PATH_URL"; | ||
|
|
||
| /// Hide progress messages with non-deterministic order in tests. | ||
| #[attr_hidden] | ||
| pub const UV_TEST_NO_CLI_PROGRESS: &'static str = "UV_TEST_NO_CLI_PROGRESS"; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -496,6 +496,48 @@ fn add_git_private_raw() -> Result<()> { | |
| Ok(()) | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| #[cfg(feature = "git")] | ||
| async fn add_git_private_rate_limited_by_github_rest_api() -> Result<()> { | ||
| use uv_client::DEFAULT_RETRIES; | ||
|
|
||
| let context = TestContext::new("3.12"); | ||
| let token = decode_token(READ_ONLY_GITHUB_TOKEN); | ||
|
|
||
| let server = MockServer::start().await; | ||
| Mock::given(method("GET")) | ||
| .respond_with(ResponseTemplate::new(429)) | ||
| .expect(1 + u64::from(DEFAULT_RETRIES)) | ||
|
||
| .mount(&server) | ||
| .await; | ||
|
|
||
| let pyproject_toml = context.temp_dir.child("pyproject.toml"); | ||
| pyproject_toml.write_str(indoc! {r#" | ||
| [project] | ||
| name = "project" | ||
| version = "0.1.0" | ||
| requires-python = ">=3.12" | ||
| dependencies = [] | ||
| "#})?; | ||
|
|
||
| uv_snapshot!(context.filters(), context | ||
| .add() | ||
| .arg(format!("uv-private-pypackage @ git+https://{token}@github.com/astral-test/uv-private-pypackage")) | ||
| .env("UV_GITHUB_FAST_PATH_URL", server.uri()), @r" | ||
| success: true | ||
| exit_code: 0 | ||
| ----- stdout ----- | ||
|
|
||
| ----- stderr ----- | ||
| Resolved 2 packages in [TIME] | ||
| Prepared 1 package in [TIME] | ||
| Installed 1 package in [TIME] | ||
| + uv-private-pypackage==0.1.0 (from git+https://github.com/astral-test/uv-private-pypackage@d780faf0ac91257d4d5a4f0c5a0e4509608c0071) | ||
| "); | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| #[cfg(feature = "git")] | ||
| fn add_git_error() -> Result<()> { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.