{"id":13411785,"url":"https://github.com/viney-shih/go-cache","last_synced_at":"2026-02-01T02:09:39.705Z","repository":{"id":36979744,"uuid":"495685234","full_name":"viney-shih/go-cache","owner":"viney-shih","description":"A flexible multi-layer Go caching library to deal with in-memory and shared cache by adopting Cache-Aside pattern.","archived":false,"fork":false,"pushed_at":"2023-08-30T13:59:10.000Z","size":984,"stargazers_count":136,"open_issues_count":3,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-07-31T20:48:48.224Z","etag":null,"topics":["cache","cache-aside","cachemanager","caching","caching-library","distributed","go","go-cache","golang","memory-cache","multi-layer-cache","multi-level-cache","tinylfu"],"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/viney-shih.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-24T05:44:24.000Z","updated_at":"2024-07-30T11:30:39.000Z","dependencies_parsed_at":"2024-06-18T22:34:27.826Z","dependency_job_id":"4b6d54fd-72cf-4c7f-9c1e-493e366d3a1e","html_url":"https://github.com/viney-shih/go-cache","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/viney-shih/go-cache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viney-shih%2Fgo-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viney-shih%2Fgo-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viney-shih%2Fgo-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viney-shih%2Fgo-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/viney-shih","download_url":"https://codeload.github.com/viney-shih/go-cache/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viney-shih%2Fgo-cache/sbom","scorecard":{"id":922388,"data":{"date":"2025-08-11","repo":{"name":"github.com/viney-shih/go-cache","commit":"49f768117824728aa53f0ac9485c450ede7e335c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.2,"checks":[{"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":"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":"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":"Code-Review","score":4,"reason":"Found 12/29 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":"Security-Policy","score":4,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Warn: no linked content found","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"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":"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":9,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql-analysis.yml:28","Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yml:29","Warn: no topLevel permission defined: .github/workflows/codeql-analysis.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":"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/codeql-analysis.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/viney-shih/go-cache/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/viney-shih/go-cache/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:59: update your workflow using https://app.stepsecurity.io/secureworkflow/viney-shih/go-cache/codeql-analysis.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/viney-shih/go-cache/codeql-analysis.yml/master?enable=pin","Info:   0 out of   4 GitHub-owned 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":"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 'master'"],"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":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0603 / GHSA-hp87-p4gw-j4gq"],"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":7,"reason":"SAST tool detected but not run on all commits","details":["Info: SAST configuration detected: CodeQL","Warn: 0 commits out of 18 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-25T05:37:37.546Z","repository_id":36979744,"created_at":"2025-08-25T05:37:37.546Z","updated_at":"2025-08-25T05:37:37.546Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28964639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T01:25:30.373Z","status":"online","status_checked_at":"2026-02-01T02:00:08.102Z","response_time":56,"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","cache-aside","cachemanager","caching","caching-library","distributed","go","go-cache","golang","memory-cache","multi-layer-cache","multi-level-cache","tinylfu"],"created_at":"2024-07-30T20:01:16.906Z","updated_at":"2026-02-01T02:09:39.658Z","avatar_url":"https://github.com/viney-shih.png","language":"Go","funding_links":[],"categories":["数据库","Database","Data Integration Frameworks","Generators"],"sub_categories":["缓存","Caches"],"readme":"# go-cache\n\n[![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/viney-shih/go-cache?tab=doc)\n[![Build Status](https://app.travis-ci.com/viney-shih/go-cache.svg?branch=master)](https://app.travis-ci.com/viney-shih/go-cache)\n[![Go Report Card](https://goreportcard.com/badge/github.com/viney-shih/go-cache)](https://goreportcard.com/report/github.com/viney-shih/go-cache)\n[![codecov](https://codecov.io/gh/viney-shih/go-cache/branch/master/graph/badge.svg?token=QKRiNSU5Gn)](https://codecov.io/gh/viney-shih/go-cache)\n[![Coverage Status](https://coveralls.io/repos/github/viney-shih/go-cache/badge.svg?branch=master)](https://coveralls.io/github/viney-shih/go-cache?branch=master)\n[![Maintainability](https://api.codeclimate.com/v1/badges/5b70576957b8af88de6e/maintainability)](https://codeclimate.com/github/viney-shih/go-cache/maintainability)\n[![Sourcegraph](https://sourcegraph.com/github.com/viney-shih/go-cache/-/badge.svg)](https://sourcegraph.com/github.com/viney-shih/go-cache?badge)\n[![License](http://img.shields.io/badge/License-Apache_2-red.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fviney-shih%2Fgo-cache.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fviney-shih%2Fgo-cache?ref=badge_shield)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#caches)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" title=\"viney-shih/go-cache\" /\u003e\n  \u003cspan style=\"font-size: 14px; font-weight: 400; color: rgba(117, 117, 117, 1); font-family: sohne, \"Helvetica Neue\", Helvetica, Arial, sans-serif;\"\u003ePhoto by \u003ca href=\"https://github.com/ashleymcnamara\"\u003eAshley McNamara\u003c/a\u003e, via \u003ca href=\"https://github.com/ashleymcnamara/gophers\"\u003eashleymcnamara/gophers\u003c/a\u003e (CC BY-NC-SA 4.0)\u003c/span\u003e\n\u003c/p\u003e\n\nA flexible multi-layered caching library interacts with **private (in-memory) cache** and **shared cache** (i.e. Redis) in Go. It provides `Cache-Aside` strategy when dealing with both, and maintains the consistency of private cache between distributed systems by `Pub-Sub` pattern.\n\nCaching is a common technique that aims to improve the performance and scalability of a system. It does this by temporarily copying frequently accessed data to fast storage close to the application. Distributed applications typically implement either or both of the following strategies when caching data:\n- Using a **private cache**, where data is held locally on the computer that's running an instance of an application or service.\n- Using a **shared cache**, serving as a common source that can be accessed by multiple processes and machines.\n\n![Using a local private cache with a shared cache](./doc/img/caching.png)\nRef: [https://docs.microsoft.com/en-us/azure/architecture/best-practices/images/caching/caching3.png](https://docs.microsoft.com/en-us/azure/architecture/best-practices/images/caching/caching3.png \"Using a local private cache with a shared cache\")\n\nConsidering the flexibility, efficiency and consistency, we starts to build up our own framework.\n\n## Features\n- **Easy to use** : provide a friendly interface to deal with both caching mechnaism by simple configuration. Limit the size of memory on single instance (pod) as well.\n- **Maintain consistency** : evict keys between distributed systems by `Pub-Sub` pattern.  \n- **Data compression** : provide customized marshal and unmarshal functions.\n- **Fix concurrency issue** : prevent data racing happened on single instance (pod).\n- **Metric** : provide callback functions to measure the performance. (i.e. hit rate, private cache usage, ...)\n\n## Data flow\n### Load the cache with `Cache-Aside` strategy\n```mermaid\nsequenceDiagram\n    participant APP as Application\n    participant M as go-cache\n    participant L as Local Cache\n    participant S as Shared Cache\n    participant R as Resource (Microservice / DB)\n    \n    APP -\u003e\u003e M: Cache.Get() / Cache.MGet()\n    alt Local Cache hit\n        M -\u003e\u003e L: Adapter.MGet()\n        L --\u003e\u003e M: {[]Value, error}\n        M --\u003e\u003e APP: return\n    else Local Cache miss but Shared Cache hit\n        M -\u003e\u003e L: Adapter.MGet()\n        L --\u003e\u003e M: cache miss\n        M -\u003e\u003e S: Adapter.MGet()\n        S --\u003e\u003e M: {[]Value, error}\n        M -\u003e\u003e L: Adapter.MSet()\n        M --\u003e\u003e APP: return\n    else All miss\n        M -\u003e\u003e L: Adapter.MGet()\n        L --\u003e\u003e M: cache miss\n        M -\u003e\u003e S: Adapter.MGet()\n        S --\u003e\u003e M: cache miss\n        M -\u003e\u003e R: OneTimeGetterFunc() / MGetterFunc()\n        R --\u003e\u003e M: return from getter\n        M -\u003e\u003e S: Adapter.MSet()\n        M -\u003e\u003e L: Adapter.MSet()\n        M --\u003e\u003e APP: return\n    end\n\n```\n\n### Evict the cache\n```mermaid\nsequenceDiagram\n    participant APP as Application\n    participant M as go-cache\n    participant L as Local Cache\n    participant S as Shared Cache\n    participant PS as PubSub\n    \n    APP -\u003e\u003e M: Cache.Del()\n    M -\u003e\u003e S: Adapter.Del()\n    S --\u003e\u003e M: return error if necessary\n    M -\u003e\u003e L: Adapter.Del()\n    L --\u003e\u003e M: return error if necessary\n    M -\u003e\u003e PS: Pubsub.Pub() (broadcast key eviction)\n    M --\u003e\u003e APP: return nil or error\n```\n\n## Installation\n```sh\ngo get github.com/viney-shih/go-cache\n```\n\n## Get Started\n### Basic usage: Set-And-Get\n\nBy adopting `Singleton` pattern, initialize the *Factory* in main.go at the beginning, and deliver it to each package or business logic.\n\n```go\n// Initialize the Factory in main.go\ntinyLfu := cache.NewTinyLFU(10000)\nrds := cache.NewRedis(redis.NewRing(\u0026redis.RingOptions{\n    Addrs: map[string]string{\n        \"server1\": \":6379\",\n    },\n}))\n\ncacheFactory := cache.NewFactory(rds, tinyLfu)\n```\n\nTreat it as a common **key:value** store like Redis. But more advanced, it coordinated the usage between multi-layered caching mechanism inside.\n\n```go\ntype Object struct {\n    Str string\n    Num int\n}\n\nfunc Example_setAndGetPattern() {\n    // We create a group of cache named \"set-and-get\".\n    // It uses the shared cache only. Each key will be expired within ten seconds.\n    c := cacheFactory.NewCache([]cache.Setting{\n        {\n            Prefix: \"set-and-get\",\n            CacheAttributes: map[cache.Type]cache.Attribute{\n                cache.SharedCacheType: {TTL: 10 * time.Second},\n            },\n        },\n    })\n\n    ctx := context.TODO()\n\n    // set the cache\n    obj := \u0026Object{\n        Str: \"value1\",\n        Num: 1,\n    }\n    if err := c.Set(ctx, \"set-and-get\", \"key\", obj); err != nil {\n        panic(\"not expected\")\n    }\n\n    // read the cache\n    container := \u0026Object{}\n    if err := c.Get(ctx, \"set-and-get\", \"key\", container); err != nil {\n        panic(\"not expected\")\n    }\n    fmt.Println(container) // Output: Object{ Str: \"value1\", Num: 1}\n\n    // read the cache but failed\n    if err := c.Get(ctx, \"set-and-get\", \"no-such-key\", container); err != nil {\n        fmt.Println(err) //  Output: errors.New(\"cache key is missing\")\n    }\n\n    // Output:\n    // \u0026{value1 1}\n    // cache key is missing\n}\n\n```\n\n### Advanced usage: `Cache-Aside` strategy\n\n`GetByFunc()` is the easier way to deal with the cache by implementing the **getter function** in the parameter. When the cache is missing, it is going to refill the cache automatically.\n\n```go\nfunc ExampleCache_GetByFunc() {\n    // We create a group of cache named \"get-by-func\".\n    // It uses the local cache only with TTL of ten minutes.\n    c := cacheFactory.NewCache([]cache.Setting{\n        {\n            Prefix: \"get-by-func\",\n            CacheAttributes: map[cache.Type]cache.Attribute{\n                cache.LocalCacheType: {TTL: 10 * time.Minute},\n            },\n            MarshalFunc:   msgpack.Marshal, // msgpack is from \"github.com/vmihailenco/msgpack/v5\"\n            UnmarshalFunc: msgpack.Unmarshal,\n        },\n    })\n\n    ctx := context.TODO()\n    container2 := \u0026Object{}\n    if err := c.GetByFunc(ctx, \"get-by-func\", \"key2\", container2, func() (interface{}, error) {\n        // The getter is used to generate data when cache missed, and refill the cache automatically..\n        // You can read from DB or other microservices.\n        // Assume we read from MySQL according to the key \"key2\" and get the value of Object{Str: \"value2\", Num: 2}\n        return Object{Str: \"value2\", Num: 2}, nil\n    }); err != nil {\n        panic(\"not expected\")\n    }\n\n    fmt.Println(container2) // Object{ Str: \"value2\", Num: 2}\n\n    // Output:\n    // \u0026{value2 2}\n}\n```\n\n`MGetter` is another approaching way to do this. Set this function durning registering the *Setting*.\n\n```go\nfunc ExampleService_Create_mGetter() {\n    // We create a group of cache named \"mgetter\".\n    // It uses both shared and local caches with separated TTL of one hour and ten minutes.\n    c := cacheFactory.NewCache([]cache.Setting{\n        {\n            Prefix: \"mgetter\",\n            CacheAttributes: map[cache.Type]cache.Attribute{\n                cache.SharedCacheType: {TTL: time.Hour},\n                cache.LocalCacheType:  {TTL: 10 * time.Minute},\n            },\n            MGetter: func(keys ...string) (interface{}, error) {\n                // The MGetter is used to generate data when cache missed, and refill the cache automatically..\n                // You can read from DB or other microservices.\n                // Assume we read from MySQL according to the key \"key3\" and get the value of Object{Str: \"value3\", Num: 3}\n                // HINT: remember to return as a slice, and the item order needs to consist with the keys in the parameters.\n                return []Object{{Str: \"value3\", Num: 3}}, nil\n            },\n            MarshalFunc:   cache.Marshal,\n            UnmarshalFunc: cache.Unmarshal,\n        },\n    })\n\n    ctx := context.TODO()\n    container3 := \u0026Object{}\n    if err := c.Get(ctx, \"mgetter\", \"key3\", container3); err != nil {\n        panic(\"not expected\")\n    }\n\n    fmt.Println(container3) // Object{ Str: \"value3\", Num: 3}\n\n    // Output:\n    // \u0026{value3 3}\n}\n```\n\n[More examples](./example_advanced_test.go)\n\n## References\n- https://docs.microsoft.com/en-us/azure/architecture/best-practices/caching\n- https://github.com/vmihailenco/go-cache-benchmark\n- https://github.com/go-redis/cache\n\n## License\n[Apache-2.0](https://opensource.org/licenses/Apache-2.0)\n\n\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fviney-shih%2Fgo-cache.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fviney-shih%2Fgo-cache?ref=badge_large)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviney-shih%2Fgo-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fviney-shih%2Fgo-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviney-shih%2Fgo-cache/lists"}