cobra icon indicating copy to clipboard operation
cobra copied to clipboard

Context.WithTimeout not stopping command or how do I stop a command

Open lpegoraro opened this issue 2 years ago • 7 comments

Hey, I was doing some benchmark test on a app, and I wanted to do e2e, calling the cobra.Command.ExecuteContext(ctx) and I setup the context with a timeout. iex: ctx, cancelFunc := context.WithTimeout(context.Background(), 2 * time.Minute)

When the timeout would hit, I was thinking that the context would be cancelling, and stopping the execution.

  1. Is that the expected behavior?
  2. If not how can I stop a execution of the Run command after it started?

lpegoraro avatar Nov 30 '22 23:11 lpegoraro

I'm not sure how familiar you are with the context timeouts in general but it doesnt interrupt execution automatically. You have to be checking a channel to see if you've had the context be cancelled/timeout for any reason. There are a number of resources you can find to show how this is done like here.

johnSchnake avatar Dec 05 '22 15:12 johnSchnake

The Cobra project currently lacks enough contributors to adequately respond to all issues. This bot triages issues and PRs according to the following rules:

  • After 60d of inactivity, lifecycle/stale is applied. - After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied and the issue is closed. You can:
  • Make a comment to remove the stale label and show your support. The 60 days reset. - If an issue has lifecycle/rotten and is closed, comment and ask maintainers if they'd be interested in reopening

github-actions[bot] avatar Feb 04 '23 00:02 github-actions[bot]

hello @johnSchnake , i am listening Done channel but still does not get timeout somehow. here is the example:

RunE: func(cmd *cobra.Command, args []string) error {
	ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second)
	defer cancel()
	cmd.SetContext(ctx)

	for i := 0; i < 20; i++ {
		time.Sleep(2 * time.Second)
		fmt.Println("hello friend, i am dancing right here")
	}

	select {
	case <-ctx.Done():
		fmt.Printf("Context cancelled: %v\n", ctx.Err())
	}

        return nil
}

I doubt that SetContext function can not set context properly. Above code exits because of timeout after 40 seconds, but i set it as 10 seconds with SetContext.

bilalcaliskan avatar Mar 29 '23 23:03 bilalcaliskan

@johnSchnake, yeah I understand and completely following up that I would be listening to the done of the context by a similar select that @bilalcaliskan exampled.

lpegoraro avatar Mar 31 '23 19:03 lpegoraro

@lpegoraro somehow this select is not working on me while using SetContext method but please let us now when you try that.

bilalcaliskan avatar Apr 06 '23 06:04 bilalcaliskan

The fact that you have to call defer cancel() once the context is set, doesn't make the usage of global command timeouts set in the rootCmd unusable?

I am asking because I am setting it in my rootCmd as follows

ctxInit := context.Background()
timeout := viper.GetInt("timeout")
ctx, cancel := context.WithTimeout(ctxInit, time.Duration(timeout)*time.Second)
defer cancel()
cmd.SetContext(ctx)

then in a subcommand

ctx := rootCmd.Context()

but ctx is context.emptyCtx {}

(unless I am passing it the wrong way)

pantelis-karamolegkos avatar Oct 23 '23 10:10 pantelis-karamolegkos

@pantelis-karamolegkos my guess is that the problem is the differ cancel (). This gets called as soon as the function in which it is called completes. The way you describe your situation. I think this gets called before the sub command.

marckhouzam avatar Oct 23 '23 11:10 marckhouzam