{"id":13411838,"url":"https://github.com/jellydator/ttlcache","last_synced_at":"2025-12-17T04:56:19.048Z","repository":{"id":24539336,"uuid":"27945817","full_name":"jellydator/ttlcache","owner":"jellydator","description":"An in-memory cache with item expiration and generics","archived":false,"fork":false,"pushed_at":"2025-11-22T18:35:30.000Z","size":284,"stargazers_count":1186,"open_issues_count":16,"forks_count":135,"subscribers_count":11,"default_branch":"v3","last_synced_at":"2025-12-03T00:53:22.720Z","etag":null,"topics":["cache","generics","golang","ttl-cache"],"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/jellydator.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":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2014-12-13T01:55:40.000Z","updated_at":"2025-12-01T14:11:35.000Z","dependencies_parsed_at":"2023-12-14T15:25:20.713Z","dependency_job_id":"b3a90221-7a0c-4e66-94bd-eb55c5b498f6","html_url":"https://github.com/jellydator/ttlcache","commit_stats":{"total_commits":187,"total_committers":24,"mean_commits":7.791666666666667,"dds":0.5401069518716577,"last_synced_commit":"77dbb071fb5f765f4d4b131625e764e4a0effa5b"},"previous_names":["renekroon/ttlcache","diegobernardes/ttlcache"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/jellydator/ttlcache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jellydator%2Fttlcache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jellydator%2Fttlcache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jellydator%2Fttlcache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jellydator%2Fttlcache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jellydator","download_url":"https://codeload.github.com/jellydator/ttlcache/tar.gz/refs/heads/v3","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jellydator%2Fttlcache/sbom","scorecard":{"id":341313,"data":{"date":"2025-08-11","repo":{"name":"github.com/jellydator/ttlcache","commit":"a21f6a646d2d08df066305d1bb1676295ff4194b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.7,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"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":"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":"Maintained","score":10,"reason":"16 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","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":8,"reason":"Found 18/22 approved changesets -- score normalized to 8","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":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:8: update your workflow using https://app.stepsecurity.io/secureworkflow/jellydator/ttlcache/go.yml/v3?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/jellydator/ttlcache/go.yml/v3?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/jellydator/ttlcache/go.yml/v3?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"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: 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":"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"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 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"}}]},"last_synced_at":"2025-08-18T05:58:10.890Z","repository_id":24539336,"created_at":"2025-08-18T05:58:10.890Z","updated_at":"2025-08-18T05:58:10.890Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27777421,"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-12-17T02:00:08.291Z","response_time":55,"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":["cache","generics","golang","ttl-cache"],"created_at":"2024-07-30T20:01:17.421Z","updated_at":"2025-12-17T04:56:19.042Z","avatar_url":"https://github.com/jellydator.png","language":"Go","funding_links":[],"categories":["Database","Go","Data Integration Frameworks","数据库","Generators"],"sub_categories":["Caches","缓存"],"readme":"## TTLCache - an in-memory cache with item expiration and generics\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/jellydator/ttlcache/v3.svg)](https://pkg.go.dev/github.com/jellydator/ttlcache/v3)\n[![Build Status](https://github.com/jellydator/ttlcache/actions/workflows/go.yml/badge.svg)](https://github.com/jellydator/ttlcache/actions/workflows/go.yml)\n[![Coverage Status](https://coveralls.io/repos/github/jellydator/ttlcache/badge.svg?branch=master)](https://coveralls.io/github/jellydator/ttlcache?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/jellydator/ttlcache/v3)](https://goreportcard.com/report/github.com/jellydator/ttlcache/v3)\n\n## Features\n- Simple API\n- Type parameters\n- Item expiration and automatic deletion\n- Automatic expiration time extension on each `Get` call\n- `Loader` interface that may be used to load/lazily initialize missing cache items\n- Thread safety\n- Event handlers (insertion, update, and eviction)\n- Metrics\n\n## Installation\n```\ngo get github.com/jellydator/ttlcache/v3\n```\n\n## Status\nThe `ttlcache` package is stable and used by [Jellydator](https://jellydator.com/), \nas well as thousands of other projects and organizations in production.\n\n## Usage\nThe main type of `ttlcache` is `Cache`. It represents a single \nin-memory data store.\n\nTo create a new instance of `ttlcache.Cache`, the `ttlcache.New()` function \nshould be called:\n```go\nfunc main() {\n\tcache := ttlcache.New[string, string]()\n}\n```\n\nNote that by default, a new cache instance does not let any of its\nitems to expire or be automatically deleted. However, this feature\ncan be activated by passing a few additional options into the \n`ttlcache.New()` function and calling the `cache.Start()` method:\n```go\nfunc main() {\n\tcache := ttlcache.New[string, string](\n\t\tttlcache.WithTTL[string, string](30 * time.Minute),\n\t)\n\n\tgo cache.Start() // starts automatic expired item deletion\n}\n```\n\nEven though the `cache.Start()` method handles expired item deletion well,\nthere may be times when the system that uses `ttlcache` needs to determine \nwhen to delete the expired items itself. For example, it may need to \ndelete them only when the resource load is at its lowest (e.g., after \nmidnight, when the number of users/HTTP requests drops). So, in situations \nlike these, instead of calling `cache.Start()`, the system could \nperiodically call `cache.DeleteExpired()`:\n```go\nfunc main() {\n\tcache := ttlcache.New[string, string](\n\t\tttlcache.WithTTL[string, string](30 * time.Minute),\n\t)\n\n\tfor {\n\t\ttime.Sleep(4 * time.Hour)\n\t\tcache.DeleteExpired()\n\t}\n}\n```\n\nThe data stored in `ttlcache.Cache` can be retrieved, checked and updated with \n`Set`, `Get`, `Delete`, `Has` etc. methods:\n```go\nfunc main() {\n\tcache := ttlcache.New[string, string](\n\t\tttlcache.WithTTL[string, string](30 * time.Minute),\n\t)\n\n\t// insert data\n\tcache.Set(\"first\", \"value1\", ttlcache.DefaultTTL)\n\tcache.Set(\"second\", \"value2\", ttlcache.NoTTL)\n\tcache.Set(\"third\", \"value3\", ttlcache.DefaultTTL)\n\n\t// retrieve data\n\titem := cache.Get(\"first\")\n\tfmt.Println(item.Value(), item.ExpiresAt())\n\n\t// check key \n\tok := cache.Has(\"third\")\n\t\n\t// delete data\n\tcache.Delete(\"second\")\n\tcache.DeleteExpired()\n\tcache.DeleteAll()\n\n\t// retrieve data if in cache otherwise insert data\n\titem, retrieved := cache.GetOrSet(\"fourth\", \"value4\", WithTTL[string, string](ttlcache.DefaultTTL))\n\n\t// retrieve and delete data\n\titem, present := cache.GetAndDelete(\"fourth\")\n}\n```\n\nTo subscribe to insertion, update and eviction events, `cache.OnInsertion()`, `cache.OnUpdate()` and \n`cache.OnEviction()` methods should be used:\n```go\nfunc main() {\n\tcache := ttlcache.New[string, string](\n\t\tttlcache.WithTTL[string, string](30 * time.Minute),\n\t\tttlcache.WithCapacity[string, string](300),\n\t)\n\n\tcache.OnInsertion(func(ctx context.Context, item *ttlcache.Item[string, string]) {\n\t\tfmt.Println(item.Value(), item.ExpiresAt())\n\t})\n\tcache.OnUpdate(func(ctx context.Context, item *ttlcache.Item[string, string]) {\n\t\tfmt.Println(item.Value(), item.ExpiresAt())\n\t})\n\tcache.OnEviction(func(ctx context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, string]) {\n\t\tif reason == ttlcache.EvictionReasonCapacityReached {\n\t\t\tfmt.Println(item.Key(), item.Value())\n\t\t}\n\t})\n\n\tcache.Set(\"first\", \"value1\", ttlcache.DefaultTTL)\n\tcache.DeleteAll()\n}\n```\n\nTo load data when the cache does not have it, a custom or\nexisting implementation of `ttlcache.Loader` can be used:\n```go\nfunc main() {\n\tloader := ttlcache.LoaderFunc[string, string](\n\t\tfunc(c *ttlcache.Cache[string, string], key string) *ttlcache.Item[string, string] {\n\t\t\t// load from file/make an HTTP request\n\t\t\titem := c.Set(\"key from file\", \"value from file\")\n\t\t\treturn item\n\t\t},\n\t)\n\tcache := ttlcache.New[string, string](\n\t\tttlcache.WithLoader[string, string](loader),\n\t)\n\n\titem := cache.Get(\"key from file\")\n}\n```\n\nTo restrict the cache's capacity based on criteria beyond the number\nof items it can hold, the `ttlcache.WithMaxCost` option allows for\nimplementing custom strategies. The following example shows how to limit\nmemory usage for cached entries to ~5KiB.\n```go\nimport (\n    \"github.com/jellydator/ttlcache\"\n)\n\nfunc main() {\n    cache := ttlcache.New[string, string](\n        ttlcache.WithMaxCost[string, string](5120, func(item ttlcache.CostItem[string, string]) uint64 {\n            // Note: The below line doesn't include memory used by internal\n            // structures or string metadata for the key and the value.\n            return uint64(len(item.Key) + len(item.Value))\n        }), \n    )\n\n    cache.Set(\"first\", \"value1\", ttlcache.DefaultTTL)\n}\n```\n\n## Examples \u0026 Tutorials\n\nSee the [example](https://github.com/jellydator/ttlcache/tree/v3/examples) \ndirectory for applications demonstrating how to use `ttlcache`.\n\nIf you want to learn and follow along as these example applications are \nbuilt, check out the tutorials below:\n- [Speeding Up HTTP Endpoints with Response Caching in Go](https://jellydator.com/blog/speeding-up-http-endpoints-with-response-caching-in-go/)\n- [Scaling Go Applications with Efficient Database Caching](https://jellydator.com/blog/scaling-go-applications-with-efficient-database-caching/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjellydator%2Fttlcache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjellydator%2Fttlcache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjellydator%2Fttlcache/lists"}