client/internal: fix Streams.Wait error handling, fix RSFilterReader error handling #52305
client/internal: fix Streams.Wait error handling, fix RSFilterReader error handling #52305thaJeztah merged 7 commits intomoby:masterfrom
Conversation
| // push/pull failures. | ||
| return jm.Error | ||
| return httpErrorFromStatusCode(jm.Error, jm.Error.Code) |
There was a problem hiding this comment.
We need to do the same in jsonmessage.Display
moby/client/pkg/jsonmessage/jsonmessage.go
Lines 132 to 135 in 9aa5ac3
Perhaps ideally, we would make this functionality part of jsonstream.Error itself, but that will add containerd/errdefs as dependency to the API.
c8e2e0b to
8aac437
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves Docker client stream handling so synchronous consumers (e.g., ImagePullResponse.Wait / ImagePushResponse.Wait) correctly surface in-band errors reported via JSON stream messages, and tightens JSON-seq reader behavior to avoid invalid (0, nil) reads.
Changes:
- Update
Stream.Wait/Stream.JSONMessagesto propagate JSON message errors and improve decode/context-cancellation handling (with errdefs-compatible wrapping). - Refine
RSfiltering reader behavior and adjustNewJSONStreamDecoderto taketypes.MediaType. - Add targeted unit tests and restore local
replacerules + vendor metadata updates.
Reviewed changes
Copilot reviewed 6 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
client/internal/jsonmessages.go |
Returns in-band stream errors from Wait, improves decode/cancel error handling, and wraps errors for errdefs classification. |
client/internal/jsonmessages_test.go |
Adds coverage for Stream.Wait success/error classification and context-cancel behavior. |
client/internal/json-stream.go |
Improves JSON stream decoder API (MediaType) and fixes RS-filter reader to avoid (0, nil) after filtering. |
client/internal/json-stream_test.go |
Expands tests for JSON-seq decoding and RSFilterReader edge-cases. |
go.mod / client/go.mod |
Restores replace rules to use local ./api, ./client (and ../api within the client submodule). |
go.sum / client/go.sum |
Removes sums for locally replaced modules. |
vendor/modules.txt |
Reflects local replaces in vendored module metadata. |
vendor/github.com/moby/moby/client/internal/jsonmessages.go |
Vendored sync of Stream.Wait / JSONMessages improvements and errdefs wrapping. |
vendor/github.com/moby/moby/client/internal/json-stream.go |
Vendored sync of MediaType decoder signature and RS filter reader fixes. |
Comments suppressed due to low confidence (1)
client/internal/json-stream.go:24
NewJSONStreamDecodernow takestypes.MediaType, but there are in-repo callers still passing astring(e.g.client/system_events.gousesresp.Header.Get("Content-Type")), which will fail to compile. Update those call-sites (and the vendored equivalents) to pass atypes.MediaTypevalue, ideally by parsing the Content-Type header (e.g., strip parameters like; charset=utf-8) before calling this function so the switch can match the expected media types.
// NewJSONStreamDecoder builds a DecoderFn to read a stream of JSON records
// formatted with the specified content-type.
func NewJSONStreamDecoder(r io.Reader, contentType types.MediaType) DecoderFn {
switch contentType {
case types.MediaTypeJSONSequence:
return json.NewDecoder(NewRSFilterReader(r)).Decode
case types.MediaTypeJSON, types.MediaTypeNDJSON, types.MediaTypeJSONLines:
fallthrough
default:
return json.NewDecoder(r).Decode
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The intent of the Wait method is to allow consumers to handle a stream synchronously; block until the push/pull/build completes (or is cancelled) but report errors happening during the stream (e.g. failures to pull the image). Wait previously ignored errors reported via jsonstream.Message.Error, causing push/pull failures to be treated as success. Update it to return these in-band errors while preserving existing handling for decode, transport, and context cancellation errors. Signed-off-by: Sebastiaan van Stijn <[email protected]>
Signed-off-by: Sebastiaan van Stijn <[email protected]>
Just slightly cleaner on scope. Signed-off-by: Sebastiaan van Stijn <[email protected]>
- explicitly return zero-values on error to prevent any potential "garbage" decoded message from being returned. - do not return decoding errors if the context was cancelled; decoding may fail due to the context being cancelled (and reader closed), which could produce unexpected errors. - consolidate all error-handling within a single `err != nil` block. Signed-off-by: Sebastiaan van Stijn <[email protected]>
This buffer was added as part of the initial implementation, but during review it was decided it's not needed; moby#50953 (comment) Remove the buffer as it's not used, and un-export the RSFilterReader implementation. Signed-off-by: Sebastiaan van Stijn <[email protected]>
RSFilterReader could consume input consisting only of RS bytes and return
(0, nil), violating io.Reader expectations. This can cause callers to loop
indefinitely waiting for progress.
For example, a caller like:
for {
n, err := r.Read(buf)
if err != nil {
return err
}
if n == 0 {
continue
}
process(buf[:n])
}
would loop forever if Read returns (0, nil) after consuming input.
Fix by continuing to read until either filtered data is available or an
error (including EOF) is returned.
Signed-off-by: Sebastiaan van Stijn <[email protected]>
Also change NewJSONStreamDecoder to use use types.MediaType as argument. The MediaType type-alias that was added in 0e7c817 to help discoverability of accepted media/content-types. Signed-off-by: Sebastiaan van Stijn <[email protected]>
|
cc @vvoland @crazy-max ptal 🤗 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 6 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
relates to:
go.mod: add back replace rules
client/internal: Stream.Wait: fix missing error-handling
The intent of the Wait method is to allow consumers to handle a stream
synchronously; block until the push/pull/build completes (or is cancelled)
but report errors happening during the stream (e.g. failures to pull the
image).
Wait previously ignored errors reported via jsonstream.Message.Error,
causing push/pull failures to be treated as success. Update it to return
these in-band errors while preserving existing handling for decode,
transport, and context cancellation errors.
client/internal: Stream.Wait: return errdefs errors
client/internal: Stream.JSONMessages: move reader inside the func
Just slightly cleaner on scope.
client/internal: Stream.JSONMessages: improve error handling
decoded message from being returned.
fail due to the context being cancelled (and reader closed), which could
produce unexpected errors.
err != nilblock.client/internal: RSFilterReader: un-export, and remove unused buffer
This buffer was added as part of the initial implementation, but during
review it was decided it's not needed; #50953 (comment)
Remove the buffer as it's not used, and un-export the RSFilterReader
implementation.
client/internal: improve test-coverage for rsFilterReader
client/internal: fix RSFilterReader returning (0, nil) after filtering
RSFilterReader could consume input consisting only of RS bytes and return
(0, nil), violating io.Reader expectations. This can cause callers to loop
indefinitely waiting for progress.
For example, a caller like:
would loop forever if Read returns (0, nil) after consuming input.
Fix by continuing to read until either filtered data is available or an
error (including EOF) is returned.
client/internal: touch-up godoc
Also change NewJSONStreamDecoder to use use types.MediaType as argument. The
MediaType type-alias that was added in 0e7c817
to help discoverability of accepted media/content-types.
- Human readable description for the release notes
- A picture of a cute animal (not mandatory but encouraged)