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
- Is it bad to create the connection in one function and close it in another function?
- Does it make sense to save the client in
viper
or is it better to create a new one in each sub-command'sRun
function?
All source code is in this repo