Skip to content

daichitakahashi/deps

Repository files navigation

deps

Go Reference coverage

Manage lifecycle of the application's dependencies and shutdown gracefully, with minimalistic API.

How to use

Create application entrypoint using deps.New() and describe dependencies with Dependent().

func main() {
	root := deps.New()

	// Worker #1 (Web server)
	go func(dep *deps.Dependency) {
		var (
			svr http.Server
			err error
			e   = make(chan error, 1)
		)
		defer dep.Stop(&err) // request abort if err!=nil

		go func() {
			e <- svr.ListenAndServe()
		}()
		select {
		case err = <-e:
			log.Println("server stopped unexpectedly: ", err)
		case <-dep.Aborted():
			log.Println("start shutdown server")
			// do not pass shutdown error to dep.Stop()
			if shutdownErr := svr.Shutdown(dep.AbortContext()); shutdownErr != nil { // timeout=1m
				log.Println("failed to shutdown server gracefully: ", shutdownErr)
			}
		}
	}(root.Dependent())

	// Worker #2 (Periodic task runner or something)
	go func(dep *deps.Dependency) {
		defer dep.Stop(nil)

		// Start worker and describe shutdown flow as same as Worker #1...
	}(root.Dependent())

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt)

	select {
	case <-root.AbortRequested():
		log.Println("abort: server error")
	case s := <-sig:
		log.Printf("abort: signal received (%s)", s.String())
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	err := root.Abort(ctx)
	if err != nil {
		log.Fatal(err)
	}
}