将grpc客户端包装在cobra命令后面的正确方法是什么?

I am implementing a GRPC client using cobra. Different service calls are behind the sub-commands.

To avoid code duplication, I keep a single connection and single client in the viper singleton. But I am not sure that's the proper way to do it.

Right now, in cmd/root.go::initConfig(), I create the connection and client and save them.

conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
    log.Fatalf("did not connect: %v", err)
}
c := pb.NewCommandClient(conn)

viper.SetDefault("Client", c)
viper.SetDefault("Connection", conn)

The connection is closed in rootCmd.PersistentPostRun(), defined in the same root.go file.

PersistentPostRun: func(cmd *cobra.Command, args []string) {
    conn := viper.Get("Connection").(*grpc.ClientConn)
    conn.Close()
},

And the client is retrieved from viper and used in the sub-commands' Run files, for example,

c := viper.Get("Client").(pb.CommandClient)
c.DoSomething() // call the service functions on c

This implementation works but I am not sure it is good practice. Specifically

  1. Is it bad to create the connection in one function and close it in another function?
  2. Does it make sense to save the client in viper or is it better to create a new one in each sub-command's Run function?

All source code is in this repo