Use a cancelReadCloser to automatically close the reader when the context
is cancelled. Consumers are still recommended to manually close the reader,
but the cancelReadCloser makes the Close idempotent.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -27,9 +27,14 @@ type TaskLogsResult interface {
|
| 27 | 27 |
io.ReadCloser |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-// TaskLogs returns the logs generated by a task. |
|
| 31 |
-// It's up to the caller to close the stream. |
|
| 30 |
+// TaskLogs returns the logs generated by a service in a [TaskLogsResult]. |
|
| 31 |
+// as an [io.ReadCloser]. Callers should close the stream. |
|
| 32 |
+// |
|
| 33 |
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled, |
|
| 32 | 34 |
func (cli *Client) TaskLogs(ctx context.Context, taskID string, options TaskLogsOptions) (TaskLogsResult, error) {
|
| 35 |
+ // TODO(thaJeztah): this function needs documentation about the format of ths stream (similar to for container logs) |
|
| 36 |
+ // TODO(thaJeztah): migrate CLI utilities to the client where suitable; https://github.com/docker/cli/blob/v29.0.0-rc.1/cli/command/service/logs.go#L73-L348 |
|
| 37 |
+ |
|
| 33 | 38 |
query := url.Values{}
|
| 34 | 39 |
if options.ShowStdout {
|
| 35 | 40 |
query.Set("stdout", "1")
|
| ... | ... |
@@ -65,30 +70,15 @@ func (cli *Client) TaskLogs(ctx context.Context, taskID string, options TaskLogs |
| 65 | 65 |
return nil, err |
| 66 | 66 |
} |
| 67 | 67 |
return &taskLogsResult{
|
| 68 |
- body: resp.Body, |
|
| 68 |
+ ReadCloser: newCancelReadCloser(ctx, resp.Body), |
|
| 69 | 69 |
}, nil |
| 70 | 70 |
} |
| 71 | 71 |
|
| 72 | 72 |
type taskLogsResult struct {
|
| 73 |
- // body must be closed to avoid a resource leak |
|
| 74 |
- body io.ReadCloser |
|
| 73 |
+ io.ReadCloser |
|
| 75 | 74 |
} |
| 76 | 75 |
|
| 77 | 76 |
var ( |
| 78 | 77 |
_ io.ReadCloser = (*taskLogsResult)(nil) |
| 79 | 78 |
_ ContainerLogsResult = (*taskLogsResult)(nil) |
| 80 | 79 |
) |
| 81 |
- |
|
| 82 |
-func (r *taskLogsResult) Read(p []byte) (int, error) {
|
|
| 83 |
- if r == nil || r.body == nil {
|
|
| 84 |
- return 0, io.EOF |
|
| 85 |
- } |
|
| 86 |
- return r.body.Read(p) |
|
| 87 |
-} |
|
| 88 |
- |
|
| 89 |
-func (r *taskLogsResult) Close() error {
|
|
| 90 |
- if r == nil || r.body == nil {
|
|
| 91 |
- return nil |
|
| 92 |
- } |
|
| 93 |
- return r.body.Close() |
|
| 94 |
-} |
| ... | ... |
@@ -27,9 +27,14 @@ type TaskLogsResult interface {
|
| 27 | 27 |
io.ReadCloser |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-// TaskLogs returns the logs generated by a task. |
|
| 31 |
-// It's up to the caller to close the stream. |
|
| 30 |
+// TaskLogs returns the logs generated by a service in a [TaskLogsResult]. |
|
| 31 |
+// as an [io.ReadCloser]. Callers should close the stream. |
|
| 32 |
+// |
|
| 33 |
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled, |
|
| 32 | 34 |
func (cli *Client) TaskLogs(ctx context.Context, taskID string, options TaskLogsOptions) (TaskLogsResult, error) {
|
| 35 |
+ // TODO(thaJeztah): this function needs documentation about the format of ths stream (similar to for container logs) |
|
| 36 |
+ // TODO(thaJeztah): migrate CLI utilities to the client where suitable; https://github.com/docker/cli/blob/v29.0.0-rc.1/cli/command/service/logs.go#L73-L348 |
|
| 37 |
+ |
|
| 33 | 38 |
query := url.Values{}
|
| 34 | 39 |
if options.ShowStdout {
|
| 35 | 40 |
query.Set("stdout", "1")
|
| ... | ... |
@@ -65,30 +70,15 @@ func (cli *Client) TaskLogs(ctx context.Context, taskID string, options TaskLogs |
| 65 | 65 |
return nil, err |
| 66 | 66 |
} |
| 67 | 67 |
return &taskLogsResult{
|
| 68 |
- body: resp.Body, |
|
| 68 |
+ ReadCloser: newCancelReadCloser(ctx, resp.Body), |
|
| 69 | 69 |
}, nil |
| 70 | 70 |
} |
| 71 | 71 |
|
| 72 | 72 |
type taskLogsResult struct {
|
| 73 |
- // body must be closed to avoid a resource leak |
|
| 74 |
- body io.ReadCloser |
|
| 73 |
+ io.ReadCloser |
|
| 75 | 74 |
} |
| 76 | 75 |
|
| 77 | 76 |
var ( |
| 78 | 77 |
_ io.ReadCloser = (*taskLogsResult)(nil) |
| 79 | 78 |
_ ContainerLogsResult = (*taskLogsResult)(nil) |
| 80 | 79 |
) |
| 81 |
- |
|
| 82 |
-func (r *taskLogsResult) Read(p []byte) (int, error) {
|
|
| 83 |
- if r == nil || r.body == nil {
|
|
| 84 |
- return 0, io.EOF |
|
| 85 |
- } |
|
| 86 |
- return r.body.Read(p) |
|
| 87 |
-} |
|
| 88 |
- |
|
| 89 |
-func (r *taskLogsResult) Close() error {
|
|
| 90 |
- if r == nil || r.body == nil {
|
|
| 91 |
- return nil |
|
| 92 |
- } |
|
| 93 |
- return r.body.Close() |
|
| 94 |
-} |