{"id":17683032,"url":"https://github.com/shomali11/fridge","last_synced_at":"2025-08-23T02:34:34.896Z","repository":{"id":57523917,"uuid":"98478828","full_name":"shomali11/fridge","owner":"shomali11","description":"A cache that resembles storing, restocking and retrieving items from a fridge","archived":false,"fork":false,"pushed_at":"2019-06-08T15:03:38.000Z","size":204,"stargazers_count":15,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-13T03:49:07.543Z","etag":null,"topics":["best-by","cache","cache-storage","cold","expired","fresh","fridge","hot","memory","redis","use-by"],"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/shomali11.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":"2017-07-27T01:05:27.000Z","updated_at":"2025-01-20T19:14:44.000Z","dependencies_parsed_at":"2022-09-15T18:24:05.678Z","dependency_job_id":null,"html_url":"https://github.com/shomali11/fridge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shomali11%2Ffridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shomali11%2Ffridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shomali11%2Ffridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shomali11%2Ffridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shomali11","download_url":"https://codeload.github.com/shomali11/fridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253843167,"owners_count":21972868,"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","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":["best-by","cache","cache-storage","cold","expired","fresh","fridge","hot","memory","redis","use-by"],"created_at":"2024-10-24T09:44:10.087Z","updated_at":"2025-05-12T23:51:35.550Z","avatar_url":"https://github.com/shomali11.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fridge [![Build Status](https://travis-ci.com/shomali11/fridge.svg?branch=master)](https://travis-ci.com/shomali11/fridge) [![Go Report Card](https://goreportcard.com/badge/github.com/shomali11/fridge)](https://goreportcard.com/report/github.com/shomali11/fridge) [![GoDoc](https://godoc.org/github.com/shomali11/fridge?status.svg)](https://godoc.org/github.com/shomali11/fridge) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n`fridge` is a layer applied on top of a cache that makes interacting with it similar to interacting with a fridge.\nItems are tagged with a \"Best By\" and \"Use By\" timestamps, stored, restocked and retrieved.\n\nTypically when using a cache, one would store some value along with a timeout.\nThe value could be retrieved from the cache as long as it has not expired.\nIf the value had expired, then an external call _(Such as a database query)_ is usually made to retrieve the value, put it back in the cache and return it.\n\nWith `fridge`, we are taking a slightly different approach.\nBefore storing a value in the `fridge`, one tags its key with a **Best By** and a **Use By** durations.\nWhen retrieving the value, a **Restock** function can be provided to refresh the value.\n\nWhen attempting to retrieve a value from the `fridge`, there are multiple scenarios that could happen:\n * If the item has not passed its **Best By** duration _(it is **fresh**)_\n   * Then the item is returned immediately.\n * If the item has passed its **Best By** duration but not its **Use By** duration _(Not **fresh** but not **expired** either)_\n   * Then the item is returned immediately \n   * But the **Restock** function is called **asynchronously** to **refresh** the item.\n * If the item has passed its **Use By** duration _(it has **expired**)_\n   * The **Restock** function is called **synchronously** to retrieve a fresh item and return it.\n * If the item was not found\n   * It is treated similarly to an expired item\n   * The **Restock** function is called **synchronously** to retrieve a fresh item and return it.\n\n## Why?\n\nThe thinking behind `fridge` is to increase the chances for a value to be retrieved from the cache.\nThe longer the value stays in the cache, the better the chances are to retrieve it faster (As opposed to from the database)\n\nThe challenge, of course, is to keep the value in the cache \"fresh\".\n\n## Dependencies\n\n* `parallelizer` [github.com/shomali11/parallelizer](https://github.com/shomali11/parallelizer)\n* `eventbus` [github.com/shomali11/eventbus](https://github.com/shomali11/eventbus)\n* `xredis` [github.com/shomali11/xredis](https://github.com/shomali11/xredis)\n* `util` [github.com/shomali11/util](https://github.com/shomali11/util)\n\n\n# Examples\n\n## Example 1\n\nUsing `NewClient` to create a new fridge client.\n_Note: `NewClient` accepts an object that implements the `Cache` interface which allows the user to use `fridge ` with any underlying implementation._\n\n```go\n// Cache is a Fridge cache interface\ntype Cache interface {\n\t// Get a value by key\n\tGet(key string) (string, bool, error)\n\n\t// Set a key value pair\n\tSet(key string, value string, timeout time.Duration) error\n\n\t// Remove a key\n\tRemove(key string) error\n\n\t// Ping to test connectivity\n\tPing() error\n\n\t// Close to close resources\n\tClose() error\n}\n```\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n\t\"time\"\n)\n\ntype SimpleCache struct {\n\tmemory map[string]string\n}\n\nfunc (c *SimpleCache) Get(key string) (string, bool, error) {\n\tvalue, ok := c.memory[key]\n\treturn value, ok, nil\n}\n\nfunc (c *SimpleCache) Set(key string, value string, timeout time.Duration) error {\n\t// We are not implementing the expiration to keep the example simple\n\tc.memory[key] = value\n\treturn nil\n}\n\nfunc (c *SimpleCache) Remove(key string) error {\n\tdelete(c.memory, key)\n\treturn nil\n}\n\nfunc (c *SimpleCache) Ping() error {\n\treturn nil\n}\n\nfunc (c *SimpleCache) Close() error {\n\treturn nil\n}\n\nfunc main() {\n\tsimpleCache := \u0026SimpleCache{memory: make(map[string]string)}\n\tclient := fridge.NewClient(simpleCache)\n\n\tfmt.Println(client.Ping())\n}\n```\n\n## Example 2\n\nUsing `NewRedisCache` to use `fridge` with redis. _Note: `NewRedisCache` creates an redis client that implements the `Cache` interface_\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache()\n\tclient := fridge.NewClient(redisCache)\n\tdefer client.Close()\n\n\tfmt.Println(client.Ping())\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\n```\n\n## Example 3\n\nUsing `NewRedisCache` with modified settings for a redis client\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache(\n\t\tfridge.WithHost(\"localhost\"), \n\t\tfridge.WithPort(6379))\n\t\t\n\tclient := fridge.NewClient(redisCache)\n\tdefer client.Close()\n\n\tfmt.Println(client.Ping())\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\n```\n\n## Example 4\n\nUsing `NewSentinelCache` with modified settings for a redis sentinel client. _Note: `NewSentinelCache` creates an redis sentinel client that implements the `Cache` interface_\n\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewSentinelCache(\n\t\tfridge.WithSentinelAddresses([]string{\"localhost:26379\"}),\n\t\tfridge.WithSentinelMasterName(\"master\"))\n\n\tclient := fridge.NewClient(redisCache)\n\tdefer client.Close()\n\n\tfmt.Println(client.Ping())\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\n```\n\n## Example 5\n\nUsing `Put`, `Get` \u0026 `Remove` to show how to put, get and remove an item.\n_Note: That we are using a default client that has a default Best By of 1 hour and Use By of 1 Day for all keys_\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache()\n\tclient := fridge.NewClient(redisCache)\n\tdefer client.Close()\n\n\tfmt.Println(client.Put(\"food\", \"Pizza\"))\n\tfmt.Println(client.Get(\"food\"))\n\tfmt.Println(client.Remove(\"food\"))\n\tfmt.Println(client.Get(\"food\"))\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\nPizza true \u003cnil\u003e\n\u003cnil\u003e\n false \u003cnil\u003e\n```\n\n## Example 6\n\nUsing `WithDefaultDurations` to override the default Best By and Use By durations for all keys\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n\t\"time\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache()\n\tclient := fridge.NewClient(redisCache, fridge.WithDefaultDurations(time.Second, 2*time.Second))\n\tdefer client.Close()\n\n\tfmt.Println(client.Put(\"food\", \"Pizza\"))\n\tfmt.Println(client.Get(\"food\"))\n\n\ttime.Sleep(time.Second)\n\n\tfmt.Println(client.Get(\"food\"))\n\n\ttime.Sleep(2 * time.Second)\n\n\tfmt.Println(client.Get(\"food\"))\n\tfmt.Println(client.Remove(\"food\"))\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\nPizza true \u003cnil\u003e\nPizza true \u003cnil\u003e\n false \u003cnil\u003e\n\u003cnil\u003e\n```\n\n## Example 7\n\nUsing `Put` to show how to put an item and override that item's durations.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n\t\"time\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache()\n\tclient := fridge.NewClient(redisCache)\n\tdefer client.Close()\n\n\tfmt.Println(client.Put(\"food\", \"Pizza\", fridge.WithDurations(time.Second, 2*time.Second)))\n\tfmt.Println(client.Get(\"food\"))\n\n\ttime.Sleep(time.Second)\n\n\tfmt.Println(client.Get(\"food\"))\n\n\ttime.Sleep(2 * time.Second)\n\n\tfmt.Println(client.Get(\"food\"))\n\tfmt.Println(client.Remove(\"food\"))\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\nPizza true \u003cnil\u003e\nPizza true \u003cnil\u003e\n false \u003cnil\u003e\n\u003cnil\u003e\n```\n\n## Example 8\n\nUsing `Get` to show how to retrieve an item while providing a restocking mechanism.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n\t\"time\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache()\n\tclient := fridge.NewClient(redisCache)\n\tdefer client.Close()\n\n\trestock := func() (string, error) {\n\t\treturn \"Hot Pizza\", nil\n\t}\n\n\tfmt.Println(client.Put(\"food\", \"Pizza\", fridge.WithDurations(time.Second, 2*time.Second)))\n\tfmt.Println(client.Get(\"food\", fridge.WithRestock(restock)))\n\n\ttime.Sleep(time.Second)\n\n\tfmt.Println(client.Get(\"food\", fridge.WithRestock(restock)))\n\n\ttime.Sleep(2 * time.Second)\n\n\tfmt.Println(client.Get(\"food\", fridge.WithRestock(restock)))\n\tfmt.Println(client.Remove(\"food\"))\n}\n```\n\nOutput\n\n```\n\u003cnil\u003e\nPizza true \u003cnil\u003e\nPizza true \u003cnil\u003e\nHot Pizza true \u003cnil\u003e\n\u003cnil\u003e\n```\n\n## Example 9\n\nUsing `HandleEvent` to pass a callback to access the stream of events generated\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/shomali11/fridge\"\n\t\"time\"\n)\n\nfunc main() {\n\tredisCache := fridge.NewRedisCache()\n\tclient := fridge.NewClient(redisCache, fridge.WithDefaultDurations(time.Second, 2*time.Second))\n\tdefer client.Close()\n\n\tclient.HandleEvent(func(event *fridge.Event) {\n\t\tfmt.Print(\"Key: \" + event.Key + \" - \")\n\n\t\tswitch event.Type {\n\t\tcase fridge.Fresh:\n\t\t\tfmt.Println(\"Woohoo! it is fresh!\")\n\t\tcase fridge.Cold:\n\t\t\tfmt.Println(\"Not fresh! But not bad either!\")\n\t\tcase fridge.Expired:\n\t\t\tfmt.Println(\"Sigh. It has expired!\")\n\t\tcase fridge.NotFound:\n\t\t\tfmt.Println(\"Oops! Did not find it.\")\n\t\tcase fridge.Restock:\n\t\t\tfmt.Println(\"Yay! Getting a new one!\")\n\t\tcase fridge.OutOfStock:\n\t\t\tfmt.Println(\"Oh no! It is out of stock.\")\n\t\tcase fridge.Unchanged:\n\t\t\tfmt.Println(\"Interesting! It has not changed.\")\n\t\t}\n\t})\n\n\trestock := func() (string, error) {\n\t\treturn \"Pizza\", nil\n\t}\n\n\tclient.Put(\"food1\", \"Pizza\")\n\tclient.Put(\"food2\", \"Milk\")\n\n\tclient.Get(\"food1\", fridge.WithRestock(restock))\n\tclient.Get(\"food2\")\n\tclient.Get(\"food3\")\n\n\ttime.Sleep(time.Second)\n\n\tclient.Get(\"food1\", fridge.WithRestock(restock))\n\tclient.Get(\"food2\")\n\tclient.Get(\"food3\")\n\n\ttime.Sleep(2 * time.Second)\n\n\tclient.Get(\"food1\", fridge.WithRestock(restock))\n\tclient.Get(\"food2\")\n\tclient.Get(\"food3\")\n\n\tclient.Remove(\"food1\")\n\tclient.Remove(\"food2\")\n\tclient.Remove(\"food3\")\n}\n```\n\nOutput:\n\n```\nKey: food1 - Woohoo! it is fresh!\nKey: food2 - Woohoo! it is fresh!\nKey: food3 - Oops! Did not find it.\nKey: food1 - Not fresh! But not bad either!\nKey: food1 - Yay! Getting a new one!\nKey: food1 - Interesting! It has not changed.\nKey: food2 - Not fresh! But not bad either!\nKey: food2 - Oh no! It is out of stock.\nKey: food3 - Oops! Did not find it.\nKey: food1 - Sigh. It has expired!\nKey: food1 - Yay! Getting a new one!\nKey: food2 - Sigh. It has expired!\nKey: food2 - Oh no! It is out of stock.\nKey: food3 - Oops! Did not find it.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshomali11%2Ffridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshomali11%2Ffridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshomali11%2Ffridge/lists"}