{"record":{"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/a105acad6c1e4576a77f01e02973f67e962bb58d/services.go#L110-L146","documentation":"Collected (not immediately returned) by shutdownServices() when ctx.Err() is non-nil at the top of an iteration. Because shutdown is best-effort, Fiber continues trying to terminate remaining services and appends this wrapped context error to the joined result rather than aborting.","triggerScenarios":"Shutdown context (from ServicesShutdownContextProvider) is canceled or expired while services are still being terminated. A long-running Terminate() on an earlier service consumed the deadline, leaving none for later ones.","commonSituations":"Shutdown deadline too tight for the service set; a service blocks in Terminate() (unclosed goroutines, hung network close); SIGTERM grace period shorter than total termination time.","solutions":["Increase the shutdown context deadline via ServicesShutdownContextProvider.","Make each service's Terminate() honor ctx and fail fast rather than blocking.","Order services so dependents terminate before dependencies if the State ordering does not already.","Profile Terminate() latency per service to find the slow one."],"exampleFix":"// before — default background context, no deadline, tight server grace\napp.Shutdown()\n// a slow Terminate consumes time, later services see canceled ctx\n\n// after — explicit generous shutdown context\napp := fiber.New(fiber.Config{\n    ServicesShutdownContextProvider: func() context.Context {\n        ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)\n        return ctx\n    },\n})\napp.Shutdown()","handlingStrategy":"validation","validationCode":"// Provide a generous shutdown context sized to total termination cost.\napp := fiber.New(fiber.Config{\n    ServicesShutdownContextProvider: func() context.Context {\n        ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)\n        return ctx\n    },\n})","typeGuard":null,"tryCatchPattern":"if err := app.Shutdown(); err != nil {\n    var joined interface{ Unwrap() []error }\n    if errors.As(err, &joined) {\n        for _, e := range joined.Unwrap() {\n            if errors.Is(e, context.Canceled) || errors.Is(e, context.DeadlineExceeded) {\n                log.Printf(\"shutdown truncated: %v\", e)\n            }\n        }\n    }\n}","preventionTips":["Make Terminate() honor ctx and fail fast.","Size the shutdown deadline to the slowest service's termination cost.","Drain in-flight work before returning from Terminate."],"tags":["services","shutdown","context","cancellation","best-effort"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}