Context retrieved from cobra subcommand is empty

125 views Asked by At

I want to have a global timeout (set in the rootCmd) so 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 {}

Am I doing sth wrong in terms of setting / retrieving the context?

edit

my rootCmd declaration

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
    Use:              "my-cli",
    TraverseChildren: true,
    Short:            "cli",
    PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
        var err error
        logger, err = logging.InitialiseLogger(*logLevel, *logFormat)
        if err != nil {
            return err
        }
        if err := viper.BindPFlags(cmd.Flags()); err != nil {
            return fmt.Errorf("error binding flags to %s command: %w\n", cmd.Name(), err)
        }
        if err := cloneMethodValidator(cmd); err != nil {
            return err
        }
        if err := InitConfig(false); err != nil {
            logger.Fatal("ERROR initiating configuration:\n", err)
        }
        ctxInit := context.Background()
        timeout := viper.GetInt("timeout")
        ctx, cancel := context.WithTimeout(ctxInit, time.Duration(timeout)*time.Second)
        defer cancel()
        cmd.SetContext(ctx)
        return nil
    },
}
1

There are 1 answers

0
Hamed N. On BEST ANSWER

As mentioned by @Peter, cmd and rootCmd are not the same. Cobra document describes PersistentPreRun(E):

children of this command will inherit and execute.

So cmd.SetContext(ctx) is not setting the rootCmd's context, it's setting the subcommand's context instead.

Then in a subcommand, you can use:

ctx := cmd.Context()

Instead of rootCmd.Context().