Skip to content
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

cli/command: ctx cancel should not print or produce a non zero exit code #5666

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Benehiko
Copy link
Member

@Benehiko Benehiko commented Dec 3, 2024

The user might kill the CLI through a SIGINT/SIGTERM
which cancels the main context we pass around.

Currently the context cancel error is printed
alongside any other wrapped error with a generic
exit code (125).

This patch improves on this behavior and prevents
any error from being printed when they match
context.Cancelled.

The cli.StatusError error would wrap errors but
not provide a way to unwrap them. This would lead
to situations where errors.Is would not match the underlying error.

Closes #5659

- What I did

- How I did it

- How to verify it

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@codecov-commenter
Copy link

codecov-commenter commented Dec 3, 2024

Codecov Report

Attention: Patch coverage is 29.16667% with 17 lines in your changes missing coverage. Please review.

Project coverage is 59.14%. Comparing base (5afa739) to head (d7c81a3).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5666      +/-   ##
==========================================
- Coverage   59.53%   59.14%   -0.39%     
==========================================
  Files         346      343       -3     
  Lines       29356    29347       -9     
==========================================
- Hits        17477    17358     -119     
- Misses      10909    11017     +108     
- Partials      970      972       +2     

The user might kill the CLI through a SIGINT/SIGTERM
which cancels the main context we pass around.

Currently the context cancel error is printed
alongside any other wrapped error with a generic
exit code (125).

This patch improves on this behavior and prevents
any error from being printed when they match
`context.Cancelled`.

The `cli.StatusError` error would wrap errors but
not provide a way to unwrap them. This would lead
to situations where `errors.Is` would not match the
underlying error.

Signed-off-by: Alano Terblanche <[email protected]>
@@ -6,16 +6,22 @@ import (

// StatusError reports an unsuccessful exit by a command.
type StatusError struct {
Status string
Status error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're changing this, it would make more sense to do

Suggested change
Status error
StatusError error

or

Suggested change
Status error
Cause error

However, we need to use some caution changing this. It's widely used, so we could never include this in a minor release, and even in a major we need to be careful.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to fix this without changing cli.StatusError first, and do this change separately, unless we absolutely need it to fix this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll think a bit about a solution for this, but I don't think we should concern ourselves too much with externals importing this particular package.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I don't think we should concern ourselves too much with externals importing this particular package.

For any reason in particular?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we have no SLA stating that internal packages in the CLI should never break due to external usage. I'd take the side of our duties are to Docker and Docker's users before a 3rd party using our code.

@@ -30,7 +30,7 @@ import (

func main() {
err := dockerMain(context.Background())
if err != nil && !errdefs.IsCancelled(err) {
if err != nil && !errdefs.IsCancelled(err) && !errdefs.IsContext(err) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the !errdefs.IsContext(err)? IMO I'd like to see a message telling me what happened if a request timed out or some such.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, right now I don't want to print any exit status or error message when the context is cancelled. I think it might be possible to determine if this is a sigint/sigterm vs a timeout for example.

@@ -103,13 +103,13 @@ func runRun(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, ro
// just in case the parse does not exit
if err != nil {
return cli.StatusError{
Status: withHelp(err, "run").Error(),
Status: withHelp(err, "run"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps as an intermediate (non-breaking) step, we could;

  • change withHelp to return a string (instead of error)
  • make withHelp "context-aware" and discard the error-message if it's a context error

(Haven't looked in-depth if that's an option, so take that with a grain of salt 😅)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could not try to handle this all magically, and instead handle context cancellation errors at each place where we think they occur. That would have the benefit of not hiding unexpected context cancelled errors if they're coming from somewhere a bug/an unexpected interaction. DRI is fine, but too much generalization can also be bad.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make withHelp "context-aware" and discard the error-message if it's a context error

we could, but this would mean inconsistent behavior, some places would print context cancelled and others nothing.

Comment on lines +23 to +24
// Unwrap allows wrapped errors stored in StatusError to be checked
// using `errors.Is`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unwrap doesn't allow wrapped errors to be checked using errors.Is – it allows StatusError to be checked with errors.Is (and exposes the underlying error).

Suggested change
// Unwrap allows wrapped errors stored in StatusError to be checked
// using `errors.Is`.
// Unwrap returns the wrapped error.
//
// This allows StatusError to be checked with errors.Is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, what I tried to say was: errors.Is checks for errors down the error chain. Since we wrap errors using fmt.Errorf("%w", err) and store that inside StatusError we need to check the underlying error instead of just err == StatusError.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it's just a matter of wording. IMO the GoDoc for Unwrap should explain what (from the perspective of StatusError) what Unwrap does, which specifically is "return the wrapped error – which allows checking StatusErr with errors.Is".

allows wrapped errors stored in StatusError to be checked using errors.Is. is less clear to me since it could also be interpreted as "allows you to do errors.Is on the underlying error" which isn't the case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

don't print "context canceled" errors when canceling an action (CTRL-C)
4 participants