On Tuesday, February 7, 2017 at 3:12:13 PM UTC-8, Francis Chuang wrote: > > I am working on a client library that starts a Kafka consumer to listen > for messages from a kafka stream and run some user defined handlers.* I > want the design to be "crash-only" as much as possible*, so will be > avoiding cleanups during unexpected shutdowns. >
That's sort of a curious model. Your description would make sense if you were describing an application, but you're describing a library. By building that design assumption into your library, you're limiting the possible uses of the library. That approach also makes it incredibly difficult to write unit-tests for your code. > > For example, here's a simple sketch: > > func myHandler(m client.Message) error{ > ... > } > > c := client.New(...) > c.AddHandler(myHandler) > c.Start() > > c.Start() looks like this: > > func (c *Client) Start(){ > > for{ > select{ > > case m := <-c.message: > > for _, handler := range c.handlers{ > err := handler(m) > } > } > } > } > > If the handler encounters an error, I have the following options: > - call log.Fatal() within the for _, handler := range loop. This seems to > be the simplest, but it doesn't seem right for a library to exit. > - remove the return error from the handler, and call log.Fatal() within so > that the handler terminates the whole program. > - create an error channel, have the for _, handler := range loop write > errors to that channel. In main(), have a for, select loop to read from the > error channel and call log.Fatal() there. > Only the last one seems acceptable for logic in a library. Because the decision to exit the program actually no longer belongs to the library, but to "main()", or a function called from main(). Not even clear to me that you want to call log.Fatal() there, either. Since you're talking about multiple Go routines, it sounds like you may have a race condition where multiple errors may have occurred. By calling log.Fatal(), you're guaranteeing that only one of those errors will be printed. The error message you may get may not be the most useful or relevant one, depending on the errors, and the race condition problems. Instead it seems like you might want to do proper cleanup of all the launched goroutines, and then drain the error channel in main(), and then exit. That way, you get all the error messages. > > Which of these options is the most idiomatic? > Exiting the program abruptly is not idiomatic. The one that moves that decision closest to the "main()" function seems like the best idea. Eric. > > Cheers, > Francis > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.