{"record":{"id":"4631af4adbeb3574","repo":"hashicorp/nomad","slug":"process-did-not-exit-after-15-seconds","errorCode":null,"errorMessage":"process did not exit after 15 seconds","messagePattern":"process did not exit after 15 seconds","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"drivers/shared/executor/executor.go","lineNumber":676,"sourceCode":"\t\tcase <-e.processExited:\n\t\tcase <-time.After(grace):\n\t\t\tproc.Kill()\n\t\t}\n\t} else {\n\t\tproc.Kill()\n\t}\n\n\t// Issue sigkill to the process group (if possible)\n\tif err = e.killProcessTree(proc); err != nil {\n\t\te.logger.Warn(\"failed to shutdown process group\", \"pid\", proc.Pid, \"error\", err)\n\t}\n\n\t// Wait for process to exit\n\tselect {\n\tcase <-e.processExited:\n\tcase <-time.After(time.Second * 15):\n\t\te.logger.Warn(\"process did not exit after 15 seconds\")\n\t\tmerr.Errors = append(merr.Errors, fmt.Errorf(\"process did not exit after 15 seconds\"))\n\t}\n\n\tif err = merr.ErrorOrNil(); err != nil {\n\t\t// Note that proclib in the TR shutdown may also dispatch a final platform\n\t\t// cleanup technique (e.g. cgroup kill), but if we get to the point where\n\t\t// that matters the Task was doing something naughty.\n\t\te.logger.Warn(\"failed to shutdown due to some error\", \"error\", err.Error())\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Signal sends the passed signal to the task\nfunc (e *UniversalExecutor) Signal(s os.Signal) error {\n\tif e.childCmd.Process == nil {\n\t\treturn fmt.Errorf(\"Task not yet run\")\n\t}","sourceCodeStart":658,"sourceCodeEnd":694,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/drivers/shared/executor/executor.go#L658-L694","documentation":"After sending the shutdown signal, Shutdown waits up to 15 seconds on the processExited channel. If the child has not exited by then, the executor logs a warning and appends this error to the shutdown multi-error, signaling the task ignored the kill signal and may need forced cleanup (e.g. cgroup kill).","triggerScenarios":"Calling Shutdown on a task that traps/ignores SIGINT (the default signal) and does not exit within 15 seconds; a hung or deadlocked child process; a child that spawned grandchildren keeping the process group alive.","commonSituations":"Applications that handle SIGINT interactively (shells, REPLs); zombie or stuck workers; tasks with long-running shutdown hooks exceeding the 15s window.","solutions":["Configure a signal the app actually handles (e.g. kill_signal = \"SIGTERM\") so graceful shutdown works","Fix the application to exit promptly on the shutdown signal","Rely on the subsequent forceful cleanup (cgroup kill / Kill) that follows this timeout","Increase application-level shutdown timeout handling rather than expecting the 15s wait to extend"],"exampleFix":"// before (task config)\n# no kill_signal -> defaults to SIGINT which the app ignores\n// after\nkill_signal = \"SIGTERM\"","handlingStrategy":"fallback","validationCode":"// Prefer a signal the application handles\ncfg := task.Config\nif cfg.KillSignal == \"\" {\n    cfg.KillSignal = \"SIGTERM\" // only if app handles SIGTERM better than SIGINT\n}","typeGuard":"func handlesSignal(appCmd []string, sig string) bool {\n    // out of band: inspect app docs/config; here just confirm signal is valid\n    _, ok := signals.SignalLookup[sig]\n    return ok\n}","tryCatchPattern":"if err := exec.Shutdown(); err != nil {\n    if strings.Contains(err.Error(), \"did not exit after 15 seconds\") {\n        log.Warn(\"graceful shutdown timed out; escalating to force kill\")\n        _ = exec.Kill() // fallback to hard kill / cgroup cleanup\n        return nil\n    }\n    return err\n}","preventionTips":["Configure kill_signal to match the application's documented shutdown signal","Make applications exit promptly on the shutdown signal","Avoid trapping and ignoring SIGINT/SIGTERM in task processes","Set realistic internal shutdown hooks well under 15 seconds"],"tags":["shutdown","timeout","process-lifecycle"],"backgroundTag":"graceful-shutdown-timeout","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}