-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Implement package fetch retries #25120
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
base: master
Are you sure you want to change the base?
Conversation
There are some locations where memory is being freed that wasn't being freed before. This is because, in the case of the user possibly configuring `Fetch` to retry many times, I don't want the allocator to allocate without freeing each time it attempts to refetch the network data, resulting in a memory leak.
src/Package/Fetch.zig
Outdated
@@ -90,6 +90,12 @@ latest_commit: ?git.Oid, | |||
/// the root source file. | |||
module: ?*Package.Module, | |||
|
|||
/// The number of times an HTTP request will retry if it fails | |||
retry_count: u32 = 2, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
u32 for a retry counter is wasteful. The HTTP client's redirect counter uses an u16 which still seems on the higher side, but I suppose u8 might not be enough in some particular cases. No one is going to wait for 255 retries though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference:
Lines 836 to 844 in d51d18c
/// Any value other than `not_allowed` or `unhandled` means that integer represents | |
/// how many remaining redirects are allowed. | |
pub const RedirectBehavior = enum(u16) { | |
/// The next redirect will cause an error. | |
not_allowed = 0, | |
/// Redirects are passed to the client to analyze the redirect response | |
/// directly. | |
unhandled = std.math.maxInt(u16), | |
_, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it was initially u8, but I should have bumped it up to u16 instead of u32. Fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought with it being larger than u8 though is someone might choose some arbitrarily "large" number like 1000 just so it keeps retrying for a long time. Seems silly, but not so silly that we should say "you can't do that", at least in my opinion
src/Package/Fetch.zig
Outdated
.{ response.head.status, response.head.status.phrase() orelse "" }, | ||
)); | ||
if (response.head.status != .ok) { | ||
// We only need to retry if we run into server-side errors (5xx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not true, package fetching could easily run into a 429 for example. #17472 even mentions spurious 404s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that's a good point. Fixed!
It might be useful to look at the defaults of other package managers for ideas - the cargo source has some good info about retries, including links to other resources: https://doc.rust-lang.org/nightly/nightly-rustc/src/cargo/util/network/retry.rs.html Some notes:
|
@ehaas Yeah, I also took a look at the I like that list of notes you jotted down though, so I'll start there. |
2d62411
to
58fbf12
Compare
Problem
Like in #17472, the package manager does not retry fetching when communication to the server fails in a way that could possibly be resolved by retrying the fetch.
Solution
Automatically retry the fetch in these scenarios during http fetches:
and theses scenarios during git+http fetches:
This does not expose this fetch config to the end user, for reasons you can read about in the next section. Definitely worth the conversation, but getting this PR out there as is doesn't seem like a bad idea to me.
Major Considerations
retry_count
andretry_delay_ms
). However, this proved difficult, so it is not a part of this PR. Here are some thoughts I had though:build.zig
file, because (as far as I can tell) thebuild.zig
file is not run until all the packages are fetched and ready to be built with the source code..dependencies
, like this (below) so that.retry_count
and other props apply to all dependencies, but it's still a part of the.dependencies
object. Also, this can easily be parsed by checking the type of the prop. If the type isanytype
, it's a real dep, if it's anything else, it's config code, not a real dep. Fun idea, but it's not a part of this PR and shouldn't be. Here is an example of this idea:std.Progress.Node
first for that, so this is also not implemented in this PR:Minor Considerations
Fetch
to retry many times, I don't want the allocator to allocate without freeing each time it attempts to refetch the network data, resulting in a memory leak.Fetch.initResource()
method needs to be refactored. But this PR is big enough, so it made sense to me to merge this, then do a refactor in a future PR.