2

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

nos
  • 19,875
  • 27
  • 98
  • 134
  • 1. Why would it be? Most apps do this. 2. This is a matter of opinion, but if I'm not mistaken viper is meant for configuration management, and a connection pool is definitely not configuration. So it feels a bit like an abuse to me. But that doesn't mean you should create new connections in each `Run` function. – Jonathan Hall Dec 29 '18 at 15:45
  • Where is a good place to save the connection pool and client? – nos Dec 29 '18 at 16:30
  • It's hard to say without seeing your overall architecture, but this is the sort of thing that [context](https://golang.org/pkg/context/) can be used for. – Jonathan Hall Dec 29 '18 at 16:31

0 Answers0