{"id":24341061,"url":"https://github.com/nhalstead/exitplan","last_synced_at":"2025-10-30T05:19:21.147Z","repository":{"id":47274189,"uuid":"368398615","full_name":"nhalstead/exitplan","owner":"nhalstead","description":"Golang Exit Callback for SIGINT \u0026 SIGTERM","archived":false,"fork":false,"pushed_at":"2021-09-05T17:58:33.000Z","size":50,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-11T20:22:58.219Z","etag":null,"topics":["cli","cli-app","cobra","command","command-line","commandline","go","golang","golang-application","poxis"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nhalstead.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-18T04:18:58.000Z","updated_at":"2021-09-05T17:54:39.000Z","dependencies_parsed_at":"2022-09-10T09:21:58.599Z","dependency_job_id":null,"html_url":"https://github.com/nhalstead/exitplan","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/nhalstead/exitplan","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhalstead%2Fexitplan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhalstead%2Fexitplan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhalstead%2Fexitplan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhalstead%2Fexitplan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nhalstead","download_url":"https://codeload.github.com/nhalstead/exitplan/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nhalstead%2Fexitplan/sbom","scorecard":{"id":683766,"data":{"date":"2025-08-11","repo":{"name":"github.com/nhalstead/exitplan","commit":"5f6d45f46531112230b6a925dda1746a43a73bba"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T00:01:44.075Z","repository_id":47274189,"created_at":"2025-08-22T00:01:44.075Z","updated_at":"2025-08-22T00:01:44.075Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281748750,"owners_count":26554835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cli-app","cobra","command","command-line","commandline","go","golang","golang-application","poxis"],"created_at":"2025-01-18T07:13:40.191Z","updated_at":"2025-10-30T05:19:21.132Z","avatar_url":"https://github.com/nhalstead.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Exit Plan\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/nhalstead/exitplan)](https://goreportcard.com/report/github.com/nhalstead/exitplan)\n[![GoDoc](https://godoc.org/github.com/nhalstead/exitplan?status.svg)](https://godoc.org/github.com/nhalstead/exitplan)\n\nSimple go package to help with the shutdown process within a go program by integrating with SIGINT and SIGTERM.\nThe purpose is to be used with a container orchestration software like kubernetes where heath checks are done on the pod.\n\nThis can be used with or without the use of an HTTP server serving the heath check data.\n\n## Demo and Details\n\nThis repo has the example in it already using the [cobra package](https://github.com/spf13/cobra).\n\nClone down the repo and build it.\n\nUpon running executing `exitplan test`, an HTTP server on port 8855 will be running.\n\nBrowse to [http://localhost:8855/readyz](http://localhost:8855/readyz) to check the status!\n\n---\n\nNow that the server is running, and the page is responding with \"ok\", you can now press COMMAND+C / CTRL+C in the terminal window to trigger a SIGTERM.\n\nAfter you trigger the SIGTERM, two actions take place. First a flag is set to indicate\n it's going to terminate (which changes the response for `/readyz`), then a grace period is waiting to complete.\n\nAfter the grade period has passed it kicks into action again with a timeout for the deadline of the program to exit.\nBefore reaching the deadline, goroutines are being made to call the shutdown methods that have been registered.\n\nLastly before the program exists it makes one last synchronous call to the FinalCallback.\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/nhalstead/exitplan\"\n)\n\nfunc main() {\n\n\tm := mux.NewRouter()\n\n\tsrv := \u0026http.Server{\n\t\tHandler:      m,\n\t\tAddr:         \"127.0.0.1:8855\",\n\t\tWriteTimeout: 5 * time.Second,\n\t\tReadTimeout:  5 * time.Second,\n\t}\n\n\tplan := exitplan.NewPlan()\n\tplan.Add(\"http\", srv.Shutdown)\n\n\t// Register a Request Handler on \"/readyz\" for the status.\n\tm.HandleFunc(\"/readyz\", plan.HandlerFunc).Methods(http.MethodGet)\n\n\tgo srv.ListenAndServe()\n\n\tfmt.Println(\"Server Running\")\n\tfmt.Println(\"Goto http://localhost:8855/readyz\")\n\n\tplan.Finally(func (ctx context.Context) error {\n\t\t// Do some final cool stuff before death\n\t\tfmt.Println(\"final callback made\")\n\t\treturn nil\n\t})\n\tplan.Wait(context.TODO())\n\n}\n```\n\n## Inspired By\n\n[Gracefully Shutdown your Go Application](https://alfiandnm.medium.com/gracefully-shutdown-your-go-application-9e7d5c73b5ac) by Alfian Dhimas\n\n[Graceful shutdown with Go http servers and Kubernetes rolling updates](https://medium.com/over-engineering/graceful-shutdown-with-go-http-servers-and-kubernetes-rolling-updates-6697e7db17cf) by Wayne Ashley Berry\n\n[Stackoverflow: Testing graceful shutdown on an HTTP server during a Kubernetes rollout](https://stackoverflow.com/a/58752566/5779200)\n\n[terminus *Graceful shutdown and Kubernetes readiness / liveness checks for any Node.js HTTP applications*](https://github.com/godaddy/terminus) by GoDaddy Dev Team\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnhalstead%2Fexitplan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnhalstead%2Fexitplan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnhalstead%2Fexitplan/lists"}