{"id":"48358136d5f20aa6","repo":"gofiber/fiber","slug":"service-s-terminate-w","errorCode":null,"errorMessage":"service %s terminate: %w","messagePattern":"service (.+?) terminate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"services.go","lineNumber":128,"sourceCode":"\treturn errors.Join(errs...)\n}\n\n// shutdownServices Handles the shutdown process of services for the current application.\n// Iterates over all the started services in reverse order and tries to terminate them,\n// returning an error if any error occurs.\nfunc (app *App) shutdownServices(ctx context.Context) error {\n\tif app.state.ServicesLen() == 0 {\n\t\treturn nil\n\t}\n\n\tvar errs []error\n\tfor key, srv := range app.state.Services() {\n\t\tif srv == nil {\n\t\t\treturn fmt.Errorf(\"fiber: service %q is nil\", key)\n\t\t}\n\t\tif err := ctx.Err(); err != nil {\n\t\t\t// Context is canceled, do a best effort to terminate the services.\n\t\t\terrs = append(errs, fmt.Errorf(\"service %s terminate: %w\", srv.String(), err))\n\t\t\tcontinue\n\t\t}\n\n\t\terr := srv.Terminate(ctx)\n\t\tif err != nil {\n\t\t\t// Best effort to terminate the services.\n\t\t\terrs = append(errs, fmt.Errorf(\"service %s terminate: %w\", srv.String(), err))\n\t\t\tcontinue\n\t\t}\n\n\t\t// Remove the service from the State\n\t\tapp.state.deleteService(srv)\n\t}\n\treturn errors.Join(errs...)\n}\n\n// logServices logs information about services and returns an error\n// if any configured service is nil.","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/services.go#L110-L146","documentation":"Returned by shutdownServices (services.go:128) when the shutdown context is already canceled/deadline-exceeded before a service's Terminate is called. Fiber still attempts best-effort termination of remaining services (it appends the error and continues rather than returning), wrapping ctx.Err() with the service name.","triggerScenarios":"Calling app.Shutdown with an already-canceled or short-deadline context, or the shutdown context being canceled mid-loop (e.g. SIGINT during graceful shutdown, or Config.ServicesShutdownContextProvider returning an expired context). The ctx.Err() check at services.go:126 fires.","commonSituations":"Shutdown deadline shorter than the time needed to drain in-flight requests/close DB pools; double SIGINT forcing immediate cancel; orchestrator hard-killing before graceful drain completes.","solutions":["Give app.Shutdown a generous deadline (e.g. context.WithTimeout(context.Background(), 30*time.Second)).","Configure ServicesShutdownContextProvider to return a context with adequate remaining time.","Make Service.Terminate fast and idempotent so it completes within the deadline.","Avoid double-canceling the shutdown context from signal handlers."],"exampleFix":"// before: tight shutdown deadline\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n_ = app.ShutdownWithContext(ctx)\n\n// after: deadline sized to slowest service drain\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nif err := app.ShutdownWithContext(ctx); err != nil {\n    log.Printf(\"shutdown completed with errors: %v\", err)\n}","handlingStrategy":"validation","validationCode":"shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\n_ = app.ShutdownWithContext(shutdownCtx)","typeGuard":null,"tryCatchPattern":"if err := app.ShutdownWithContext(shutdownCtx); err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n        log.Printf(\"shutdown context expired: %v\", err)\n    }\n}","preventionTips":["Use a generous shutdown deadline (longer than max drain time).","Make Service.Terminate idempotent and fast.","Avoid double-cancelling the shutdown context from signal handlers."],"tags":["services","shutdown","context","cancellation","deadline"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}