-
Notifications
You must be signed in to change notification settings - Fork 390
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
Improve progress reader to report start/end and offset update #732
Conversation
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.
Overall, sure, this works, but I’m a bit worried that it may not do quite what the caller expects.
- Is “the first time
Read
returns” really exactly the right moment? If the source is very slow, the caller won’t receive any report about trying to work with the blob until after the first data/timeout arrives. Should the first progress indication about the artifact happen at the very start ofcopyBlobFromStream
, before asking for the first byte? (Or, actually, all the way up beforeTryReusingBlob
and the like, so that it captures the delays communicating over HTTP and the like, and setting up the streams, not just waiting for data?) - Note that
PutBlob
may never actually read all of the data (well, it may not read any), e.g. if the blob already exists on the destination (well, if it was uploaded afterTryReusingBlob
fails). Should the last update be conditioned onr.artifact.Size
, or be determined by code flow using adefer
or something like that? (r.artifact.Size
can even be -1 to mean “unknown”!) And should we, in that case, somehow tell the caller that the artifact is done (by lying and sayingOffset = Size
, or by decreasingSize
)?
Neither is really a big show-stopper to me, and I’m not sure that CRI-O cares about either of the two at all. Thinking too far in this direction would lead to a complete redesign of the progress interface, which is currently rather a crude hack, to be much more detailed about the semantics, and I suppose that’s not all that needed right now — or is it?
Hey @mtrmac, thanks for the first look. My main intention was to have something which changes
I would expect (as a user) that the progress fires the first time a connection with the server (stream) has been successfully setup and no data got transferred. Maybe a progress state (
The caller needs the information that data has been skipped, because this will be an additional metric in CRI-O.
Yeah, I'm not sure. The first time I used this API I must honestly admit that I expected something different from a usage perspective. I would assume that the progress bar display is handled by a more higher level library (like podman), whereas the API here works like:
|
That’s very fair, and I don’t at at all want to insist on a big (API-breaking) redesign. It’s perfectly fine to do a small incremental improvement, as long as it’s clear that it still has limitations.
The current progress bars are handled by
Doing just these two might be easy enough in the ~current model, see the code comments: |
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 only real quibble is with the LastRead
field name; these are just possible ways to extend this PR.
copy/copy.go
Outdated
@@ -1159,7 +1159,7 @@ func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, sr | |||
channel: c.progress, | |||
interval: c.progressInterval, | |||
artifact: srcInfo, | |||
lastTime: time.Now(), | |||
lastTime: time.Time{}, |
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.
copyBlobFromStream
should ideally not need to know about the time.Time{}
special case; this rather calls for a newProgressReader()
constructor that handles that.
- That constructor could legitimately fire a “dealing with new artifact, 0% progress” event, without making this code any more complex.
- It would then be very reasonable to add a
defer func() { progressReader.reportDone(didReadAll, errorIfAny) }
or something like that (let’s not add data that no-one needs), and ensure that there really is a 100%/skipped report. - Perhaps we could also split the constructor from a
progressReader.assignSource(destStream)
call, and call the constructor earlier than here, to get the 0% indication in the right place.
(To be clear, that work was good and it would be a shame to lose it — and splitting that work into a smaller PR focused just on progress bars could help. Still, designing a well-typed stable API with detailed events about the progress is much more work than this PR.) |
daf6d55
to
42fdc78
Compare
42fdc78
to
cd6d90d
Compare
Ready for review, @mtrmac and @vrothberg PTAL. |
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.
Thanks, this is great!
I’ll probably not get to make a careful review before Tuesday, so just a quick pass — other than the test question, it’s all nits and I don’t expect anything more serious to come up.
) *progressReader { | ||
artifact := types.BlobInfo{Size: 10} | ||
|
||
go func() { |
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.
Note to self: does the testing framework know it has to wait for all spawned goroutines?
@@ -0,0 +1,94 @@ | |||
package copy |
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.
Yay, tests. Great!
cd6d90d
to
0cb2995
Compare
Needs rebase. |
0cb2995
to
01369d9
Compare
The progress reader will be now created via the new `newProgressReader` function. This way we have the possibility to trigger a new event called `ProgressEventNewArtifact` and `ProgressEventDone` to indicate the boundaries of the artifact download to the API consumer. During the download, we additionally provide the `OffsetUpdate`, which can be used to report the downloaded data during the last elapsed time interval. Unit tests have been added as well to the progress reader, whereas the documentation for the new types has been enhanced as well. Signed-off-by: Sascha Grunert <[email protected]>
01369d9
to
dbbb10b
Compare
Rebased on top of the latest master branch. |
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.
LGTM
LGTM and happy green test buttons. Would like a final head nod from @mtrmac |
Hopefully this does not require a new version? :^( |
Only a minor bump is required :) |
The progress reader will be now created via the new
newProgressReader
function. This way we have the possibility to trigger a new event called
ProgressEventNewArtifact
andProgressEventDone
to indicate theboundaries of the artifact download to the API consumer. During the
download, we additionally provide the
OffsetUpdate
, which can be usedto report the downloaded data during the last elapsed time interval.
Unit tests have been added as well to the progress reader, whereas the
documentation for the new types has been enhanced as well.
Needed for metrics improvements for CRI-O: cri-o/cri-o#2912