{"id":36784761,"url":"https://github.com/desertbit/closer","last_synced_at":"2026-01-12T13:19:57.367Z","repository":{"id":32503121,"uuid":"107417147","full_name":"desertbit/closer","owner":"desertbit","description":"A simple, thread-safe closer for go","archived":false,"fork":false,"pushed_at":"2025-07-09T20:28:17.000Z","size":89,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-08-13T22:46:58.879Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/desertbit.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,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-18T14:09:09.000Z","updated_at":"2025-07-09T20:27:14.000Z","dependencies_parsed_at":"2024-07-12T12:56:58.972Z","dependency_job_id":"91f65cdb-e306-46a1-adfa-c9140ef3ffca","html_url":"https://github.com/desertbit/closer","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/desertbit/closer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/desertbit%2Fcloser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/desertbit%2Fcloser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/desertbit%2Fcloser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/desertbit%2Fcloser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/desertbit","download_url":"https://codeload.github.com/desertbit/closer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/desertbit%2Fcloser/sbom","scorecard":{"id":336018,"data":{"date":"2025-08-11","repo":{"name":"github.com/desertbit/closer","commit":"30dc39db0ce5fdfde06f81af33eb7de5adb9ad0c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"name":"Code-Review","score":4,"reason":"Found 10/24 approved changesets -- score normalized to 4","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":"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":"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":"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":"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":"Maintained","score":0,"reason":"1 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":"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: 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":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"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 22 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-18T04:44:55.557Z","repository_id":32503121,"created_at":"2025-08-18T04:44:55.557Z","updated_at":"2025-08-18T04:44:55.557Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338996,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-01-12T13:19:57.283Z","updated_at":"2026-01-12T13:19:57.353Z","avatar_url":"https://github.com/desertbit.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Closer - A simple, thread-safe closer\n\n[![GoDoc](https://godoc.org/github.com/desertbit/closer/v4?status.svg)](https://godoc.org/github.com/desertbit/closer/v4)\n[![Go Report Card](https://goreportcard.com/badge/github.com/desertbit/closer/v4)](https://goreportcard.com/report/github.com/desertbit/closer/v4)\n[![coverage](https://codecov.io/gh/desertbit/closer/branch/master/graph/badge.svg)](https://codecov.io/gh/desertbit/closer/branch/master)\n[![license](https://img.shields.io/github/license/desertbit/closer.svg)](https://opensource.org/licenses/MIT)\n\nThis package aims to provide a simple and performance oriented mechanism to manage the graceful and reliable shutdown of an application, or parts of it.  \n\nIt can also be a handy alternative to the context package, though it does not solve the problem that common go libraries only accept context as a valid cancellation method. Therefore, you are only able to cancel \"in-between\" slow operations.\n\n```\ngo get github.com/desertbit/closer/v4\n```\n\n### Examples\nCheck out the sample program for a good overview of this package's functionality.\n##### Closing\nLet us assume you want a server that should close its connection once it gets closed. We close the connection in the `onClose()` method of the server's closer and demonstrate that it does not matter how often you call `Close()`, the connection is closed exactly once.\n\n```go\ntype Server struct {\n    closer.Closer // Embedded\n    conn net.Conn\n}\n\nfunc New() *Server {\n    // ...\n    s := \u0026Server {\n        Closer: closer.New(),\n        conn: conn,\n    }\n    closer.Hook(s, func(h closer.H) {\n        h.OnCloseWithErr(s.onClose)\n    })\n    return s\n}\n\nfunc (s *server) onClose() error {\n    return s.conn.Close()\n}\n\nfunc main() {\n    s := New()\n    // ...\n\n    // The s.onClose function will be called only once.\n    s.Close()\n    s.Close()\n}\n```\n\n##### OneWay\nNow we want an application that (among other things) connects as a client to a remote server. In case the connection is interrupted, the app should continue to run and not fail. But if the app itself closes, of course we want to take down the client connection as well.\n```go\ntype App struct {\n    closer.Closer\n}\n\nfunc NewApp() *App {\n    return \u0026App{\n        Closer: closer.New()\n    }\n}\n\ntype Client struct {\n    closer.Closer\n    conn net.Conn\n}\n\nfunc NewClient(cl closer.Closer, conn net.Conn) (c *Client) {\n    closer.Hook(s, func(h closer.H) {\n        c = \u0026Client{\n            Closer: cl,\n            conn: conn,\n        }\n        h.OnCloseWithErr(func() error {\n            return c.conn.Close()\n        })\n    })\n    return c\n}\n\nfunc main() {\n    a := NewApp()\n    // Close c, when a closes, but do not close a, when c closes.\n    c := NewClient(closer.OneWay(a))\n    \n    c.Close()\n    // App still alive.\n}\n```\n\n##### TwoWay\nOf course, there is the opposite to the OneWay closer that closes its parent as well. If we take the example from before, we can simply exchange the closer that is passed to the client.\n```go\n//...\n\nfunc main() {\n    a := NewApp()\n    // Close c, when a closes, and close a, when c closes.\n    c := NewClient(closer.TwoWay(a))\n    \n    c.Close()\n    // App has been closed.\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdesertbit%2Fcloser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdesertbit%2Fcloser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdesertbit%2Fcloser/lists"}