Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Graceful Shutdown Manager for Go

License

NotificationsYou must be signed in to change notification settings

marnixbouhuis/coda

Repository files navigation

Go ReferenceCI/CD Pipeline

Coda is a Go library that helps manage graceful shutdowns of concurrent applications. It provides a structured way to organize goroutines into groups with dependencies and ensures they shut down in the correct order.

Features

  • Group-based goroutine management
  • Dependency-based shutdown ordering
  • Configurable timeouts and behavior
  • Flexible logging options
  • Error handling and propagation

Installation

go get github.com/marnixbouhuis/coda

Quick Start

shutdown:=coda.NewShutdown()// Create groupsdbGroup:=coda.Must(shutdown.NewGroup("database",nil))workerGroup:=coda.Must(shutdown.NewGroup("worker", []*coda.Group{dbGroup}))// Add goroutines to groupsdbGroup.Go(func(ctx context.Context,readyfunc())error {// Do startup work hereready()// Wait for shutdown signal<-ctx.Done()// Do tear down logic herereturnnil})// Wait for shutdownerr:=shutdown.Wait()

Core Concepts

Shutdown Manager

The shutdown manager is the main coordinator that manages groups and their shutdown sequence. Create one usingNewShutdown().

Options:

  • WithShutdownLogger(logger Logger) - Set a custom logger (default: NoopLogger)

Groups

Groups are collections of goroutines that should be shut down together. Groups can depend on other groups, creating a shutdown hierarchy.

Create groups usingshutdown.NewGroup(name string, dependencies []*Group, opts ...GroupOption).

Group options:

  • WithGroupShutdownTimeout(duration) - Maximum time to wait for group shutdown (default: no timeout)

Goroutines

Add goroutines to groups using theGo() method. Each goroutine receives a context and a ready function.

group.Go(func(ctx context.Context,readyfunc())error {// Do startup here// Signal readinessready()// Wait for shutdown<-ctx.Done()// Do shutdown herereturnnil},opts...)

Goroutine options:

  • WithReadyTimeout(duration) - Maximum time to wait for ready signal (default: no timeout)
  • WithCrashOnReadyTimeoutHit(bool) - Stop everything if ready timeout is hit (default: true)
  • WithCrashOnError(bool) - Stop everything if goroutine returns error (default: true)
  • WithCrashOnEarlyStop(bool) - Stop everything if goroutine exits before shutdown (default: true)
  • WithBlock(bool) - Block until goroutine signals ready (default: false)

Examples

Multiple Groups with Dependencies

funcExample() {sd:=coda.NewShutdown(coda.WithShutdownLogger(coda.NewStdLogger(log.Default())),)// Create groups with dependenciesdbGroup:=coda.Must(sd.NewGroup("database",nil,coda.WithGroupShutdownTimeout(5*time.Second),))workerGroup:=coda.Must(sd.NewGroup("workers", []*coda.Group{dbGroup},coda.WithGroupShutdownTimeout(10*time.Second),))// Database connectiondbGroup.Go(func(ctx context.Context,readyfunc())error {db,err:=sql.Open("postgres","connection-string")iferr!=nil {returnerr}deferdb.Close()ready()<-ctx.Done()returnnil},coda.WithBlock(true))// Start multiple workersforworkerID:=range3 {workerGroup.Go(func(ctx context.Context,readyfunc())error {log.Printf("Worker %d starting",workerID)ready()for {select {case<-ctx.Done():log.Printf("Worker %d shutting down",workerID)returnnilcase<-time.After(time.Second):// Do some worklog.Printf("Worker %d processing",workerID)}}},coda.WithBlock(true))}serverGroup:=coda.Must(sd.NewGroup("server", []*coda.Group{workerGroup,dbGroup}))serverGroup.Go(func(ctx context.Context,readyfunc())error {ready()mux:=http.NewServeMux()srv:=&http.Server{Addr:":8080",Handler:mux,ReadTimeout:5*time.Second,WriteTimeout:10*time.Second,}mux.HandleFunc("/demo",func(w http.ResponseWriter,_*http.Request) {w.WriteHeader(http.StatusOK)})gofunc() {<-ctx.Done()shutdownCtx,cancel:=context.WithTimeout(context.WithoutCancel(ctx),time.Second*30)defercancel()iferr:=srv.Shutdown(shutdownCtx);err!=nil {log.Printf("Failed to stop HTTP server gracefully: %v",err)sd.StopWithError(err)}}()iferr:=srv.ListenAndServe();err!=nil&&!errors.Is(err,http.ErrServerClosed) {returnerr}returnnil})gofunc() {ch:=make(chan os.Signal,1)signal.Notify(ch,syscall.SIGINT,syscall.SIGTERM)<-chsd.Stop()}()iferr:=sd.Wait();err!=nil {log.Printf("Shutdown error: %v",err)os.Exit(1)}}

Error Handling

Errors can occur in several ways:

  • Goroutine returns an error
  • Ready timeout is hit
  • Goroutine stops early
  • Shutdown timeout is hit

Configure how these errors are handled using the appropriate options. Errors can either crash the entire shutdown process or be logged and ignored.

Logging

Coda supports custom logging through theLogger interface:

typeLoggerinterface {Info(strstring)Error(strstring)}

Built-in loggers:

  • NewNoopLogger() - Discards all logs (default)
  • NewStdLogger(logger *log.Logger) - Adapts standard library logger

Loggers available as external module:

License

This project is licensed under the MIT License - see theLICENSE.md file for details.


[8]ページ先頭

©2009-2025 Movatter.jp