HTTP servers should not be shut down abruptly if it can be avoided. Instead, it's better to stop accepting new requests and give any in-flight requests a chance to finish before shutting down. This is called a "graceful shutdown".
This can be accomplished in Huma using the CLI hooks.OnStop() hook, passing a function that shuts down the server with a timeout.
packagemainimport("context""fmt""net/http""time""github.com/danielgtaylor/huma/v2""github.com/danielgtaylor/huma/v2/adapters/humachi""github.com/danielgtaylor/huma/v2/humacli""github.com/go-chi/chi/v5")// Options for the CLI.typeOptionsstruct{Portint`help:"Port to listen on" short:"p" default:"8888"`}// GreetingInput represents the greeting operation request.typeGreetingInputstruct{Namestring`path:"name" maxLength:"30" example:"world" doc:"Name to greet"`}// GreetingOutput represents the greeting operation response.typeGreetingOutputstruct{Bodystruct{Messagestring`json:"message" example:"Hello, world!" doc:"Greeting message"`}}funcmain(){// Create a CLI app which takes a port option.cli:=humacli.New(func(hookshumacli.Hooks,options*Options){// Create a new router & APIrouter:=chi.NewMux()api:=humachi.New(router,huma.DefaultConfig("My API","1.0.0"))// Register GET /greeting/{name}huma.Register(api,huma.Operation{OperationID:"get-greeting",Summary:"Get a greeting",Method:http.MethodGet,Path:"/greeting/{name}",},func(ctxcontext.Context,input*GreetingInput)(*GreetingOutput,error){resp:=&GreetingOutput{}resp.Body.Message=fmt.Sprintf("Hello, %s!",input.Name)returnresp,nil})// Create the HTTP server.server:=http.Server{Addr:fmt.Sprintf(":%d",options.Port),Handler:router,}// Tell the CLI how to start your router.hooks.OnStart(func(){server.ListenAndServe()})// Tell the CLI how to stop your server.hooks.OnStop(func(){// Give the server 5 seconds to gracefully shut down, then give up.ctx,cancel:=context.WithTimeout(context.Background(),5*time.Second)defercancel()server.Shutdown(ctx)})})// Run the CLI. When passed no commands, it starts the server.cli.Run()}
Readiness Checks
If using something like Kubernetes with readiness checks, and if the readiness route is registered on the same router as your Huma APIs, then the above code will cause the readiness check to start failing and Kubernetes will no longer route new requests to the shutting down pod as the existing connections drain.