{"id":25328652,"url":"https://github.com/kit/stockpile_cache","last_synced_at":"2025-10-14T18:34:59.813Z","repository":{"id":59156521,"uuid":"207646442","full_name":"Kit/stockpile_cache","owner":"Kit","description":"Simple Redis based cache with stampede protection and multiple DB support","archived":false,"fork":false,"pushed_at":"2024-11-14T17:36:32.000Z","size":49,"stargazers_count":17,"open_issues_count":0,"forks_count":4,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-02-12T14:59:38.107Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/Kit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2019-09-10T19:30:55.000Z","updated_at":"2024-05-02T20:06:20.000Z","dependencies_parsed_at":"2025-01-01T15:14:09.075Z","dependency_job_id":"17294be0-08ee-4118-9ab2-543a12300ed9","html_url":"https://github.com/Kit/stockpile_cache","commit_stats":null,"previous_names":["convertkit/stockpile_cache"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fstockpile_cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fstockpile_cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fstockpile_cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fstockpile_cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kit","download_url":"https://codeload.github.com/Kit/stockpile_cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238772126,"owners_count":19527879,"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":[],"created_at":"2025-02-14T02:56:30.847Z","updated_at":"2025-10-14T18:34:54.762Z","avatar_url":"https://github.com/Kit.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stockpile [![Build Status][ci-image]][ci] [![Code Climate][codeclimate-image]][codeclimate] [![Gem Version][version-image]][version]\nStockpile is a simple cache written in Ruby backed by Redis. It has built in\n[cache-stampede](https://en.wikipedia.org/wiki/Cache_stampede) (also known as\ndog-piling) protection and support for multiple Redis servers.\n\nCan be used with any Ruby or Ruby on Rails project. Can be used as a replacement for\nexisting Ruby on Rails cache.\n\nIntended as a heavy usage cache to prevent concurrent execution of code when\ncache is expired that will lead to congestion collapse of your systems.\n\nUpon caching serializes cached value using [Oj](https://github.com/ohler55/oj)\ngem. While reading value from cache will deserialize value from cache using same\ngem.\n\n## How it works\nWhen `perform_cached` method is invoked with a key and a block of code as\narguments Stockpile will attempt to fetch value from cache using given key. If\nno value is returned it will set a lock deferring all other requests for given\nkey (for specified amount of time) and run provided block of code and storing\nit's return value at the key. After that a lock will be released allowing other\nrequests to fetch their values from cache.\n\nIn case there is a cache miss and an active execution lock for a given key is\npresent request will go into slumber for 2 seconds (configurable by\n`STOCKPILE_SLUMBER` environment variable or by calling `slumber` method on\nconfiguration object). During slumber request will keep trying to read value\nfrom cache and if no result is returned during that time cache will be bypassed\nand value will be computed by executing passed in block.\n\n## Installation\nAdd the following line to your Gemfile:\n\n```\ngem 'stockpile_cache'\n```\nAnd run `bundle` from your shell.\n\nTo install gem manually run from your shell:\n\n```\ngem install stockpile_cache\n```\n\n## Requirements\nOnly requirement to run this gem is [Redis](https://redis.io/). Other than that\nit is not dependant on any other framework or system.\n\n## Configration\nThe only thing you need to set up is URL of your Redis server. You can do this\nby either setting `STOCKPILE_REDIS_URL` environment variable or by executing\nfollowing code during runtime. For Ruby on Rails create\n`config/initializers/stockpile.rb` file and put the following code in there:\n\n```\nStockpile.configure do |configuration|\n  configuration.redis_url = \u003cREDIS_URL\u003e\nend\n```\n\nThere are two ways to configure Stockpile: using environment variables or\ninvoking configuration block during runtime.\n\nFollowing settings are supported:\n\n| Variable | Method | Settings |\n| ------------- | ------------- | ------------- |\n| `STOCKPILE_CONNECTION_POOL` | `connection_pool` | Redis connection pool size to share amongst the fibers or threads in your Ruby. Defaults to `100`. |\n| `STOCKPILE_CONNECTION_TIMEOUT` | `connection_timeout`  | How long to wait for a connection from connection pool to become available (in seconds). Defaults to `3`. |\n| `STOCKPILE_LOCK_EXPIRATION` | `lock_expiration` | Time to keep execution lock alive (in seonds). Defaults to `10`. |\n| `STOCKPILE_REDIS_URL` | `redis_url` | URL of your Redis server that will be used for caching. Defaults to `redis://localhost:6379/1`. |\n| `STOCKPILE_REDIS_SENTINELS` | `sentinels` | (optional) Comma separated list of Sentinels IPs for Redis. Defaults to `nil`. Example value: `8.8.8.8:42,8.8.4.4:42`. |\n| `STOCKPILE_SLUMBER` | `slumber` | Timeout (in seconds) for stampede protection lock. After timeout passed in code will be executed instead of reading a value from cache. Defaults to `2`. |\n| `STOCKPILE_CONFIGURATION_FILE` | `configuration_file` | (optional) `.yml` configuration file to read connection information from. See [Multiple Database](#multiple-database). |\n\n## Usage\nTo use simply wrap your code into `perform_cached` block:\n\n```\nStockpile.perform_cached(key: 'meaning_of_life', ttl: 42) do\n  21 + 21\nend\n```\n\n`perform` method accepts 4 named arguments:\n\n| Argument | Meaning |\n| ------------- | ------------- |\n| `key` | Pointer in cache by which a value will be either looked up or stored in cache once code provided in block is executed. |\n| `ttl` | (optional) Time in seconds for which a cached value will be stored. Defaults to 300 seconds (5 minutes). |\n| `db` | (optional) Name of the Redis database to cache value in. Defaults to `:default` |\n| `\u0026block` | Block of code to execute; it's return value will be stored in cache. |\n\nTo expire your cache immediately run:\n\n```\nStockpile.expire_cached(key: 'meaning_of_life')\n```\n\n### Multiple Database\nStockpile comes with a support for multiple databases. A word of caution: unless\nyou have very good reason to run multiple databases within single instance of\nRedis server you probably should avoid doing so as you will not see any performance\nimprovements in doing so.\n\nTo allow multi-database support you have to do two things. First you have to set\n`configuration_file` setting to point at `.yml` containing your configuration.\nYou can do so by either setting a `STOCKPILE_CONFIGURATION_FILE` environment\nvariable or by executing a configuration block during runtime (for Rails create\n`config/initializers/stockpile.rb` with following content):\n\n```\nStockpile.configure do |configuration|\n  configuration.configuration_file = \u003cPATH/TO/FILE\u003e\nend\n```\n\nSecond thing to do is to create a `.yml` configuration file. It has to have at\nleast one database definition. Providing `sentinels` is optional. Everything\nelse is mandatory:\n\n```\n---\nmaster:\n  url: 'redis://redis-1-host:6379/1'\n  sentinels: '8.8.8.8:42,8.8.4.4:42'\n  pool_options:\n    size: 5\n    timeout: 5\n\ncommander:\n  url: 'redis://redis-2-host:6379/1'\n  pool_options:\n    size: 5\n    timeout: 5\n```\n\nTo query different databases provide a corresponding `db:` param with\n`perform_cached` method:\n\n```\nStockpile.perform_cached(db: :master, key: 'meaning_of_life', ttl: 42) do\n  21 + 21\nend\n\nStockpile.perform_cached(db: :commander, key: 'meaning_of_life', ttl: 21) do\n  21\nend\n```\n\nIf you do not provide a `db:` param then a `:default` database will be used; if\nyou do not define it in a configuration file your request will error out.\n\nUsing `configuration_file` setting will make Stockpile ignore all other\nRedis connection related settings and it will read configuration from `.yml`\nfile instead.\n\n### Compression of Cached Content\nStockpile optionally supports compression of cached content; you will not see\nmuch benefit from compressing small strings but once you start caching bigger\npayloads like fragments of HTML you could see some improvements by using\ncompression. To use compression you will have to use configuration file set by\n`STOCKPILE_CONFIGURATION_FILE`.\n\nTo enable compression you have to do two things. First you have to set\n`configuration_file` setting to point at `.yml` containing your configuration.\nYou can do so by either setting a `STOCKPILE_CONFIGURATION_FILE` environment\nvariable or by executing a configuration block during runtime (for Rails create\n`config/initializers/stockpile.rb` with following content):\n\n```\nStockpile.configure do |configuration|\n  configuration.configuration_file = \u003cPATH/TO/FILE\u003e\nend\n```\n\nSecond thing to do is to create a `.yml` configuration file. It has to have at\nleast one database definition. Providing `sentinels` and `compression` is\noptional. Everything else is mandatory:\n\n\n```\n---\nmaster:\n  url: 'redis://redis-1-host:6379/1'\n  sentinels: '8.8.8.8:42,8.8.4.4:42'\n  compression: true\n  pool_options:\n    size: 5\n    timeout: 5\n```\n\nFrom that point everything that will be cached in `master` database will be\ncompressed.\n\n## Caveats\nThere is no timeout or rescue set for code you will be running through the cache. If\nyou need to do either you have to handle it outside of Stockpile.\n\nLocks are never set indefinitely and by default will expire after 10 seconds\nallowing next request to trigger cache recalculation. Lock duration is\nconfigurable by either setting `STOCKPILE_LOCK_EXPIRATION` environment variable\nor by calling `slumber` method on configuration object.\n\nWhile there is an active lock for the key each request trying to read that key\nwill wait in slumber for 2 seconds (configurable by `STOCKPILE_SLUMBER`\nenvironment variable or by calling `slumber` method on configuration object) and\nwill bypass cache after that if no value will be set in that time.\n\n## Development\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run\n`rspec` to run the tests. You can also run `bin/console` for an interactive\nprompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To\nrelease a new version, update the version number in `version.rb`, and then run\n`bundle exec rake release`, which will create a git tag for the version, push\ngit commits and tags, and push the `.gem` file to\n[rubygems.org](https://rubygems.org).\n\n## Contributing\nBug reports and pull requests are welcome on GitHub at\nhttps://github.com/ConvertKit/stockpile_cache. This project is intended to be a\nsafe, welcoming space for collaboration, and contributors are expected to adhere\nto the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\nThe gem is available as open source under the terms of the\n[Apache License Version 2.0] (http://www.apache.org/licenses/LICENSE-2.0).\n\n## Code of Conduct\nEveryone interacting in the Stockpile project’s codebases, issue\ntrackers, chat rooms and mailing lists is expected to follow the [code of\nconduct](https://github.com/ConvertKit/stockpile_cache/blob/master/CODE_OF_CONDUCT.md).\n\n[ci]: https://circleci.com/gh/ConvertKit/stockpile_cache\n[ci-image]: https://circleci.com/gh/ConvertKit/stockpile_cache.svg?style=svg\n[codeclimate]: https://codeclimate.com/github/ConvertKit/stockpile_cache/maintainability\n[codeclimate-image]: https://api.codeclimate.com/v1/badges/f9ca3b6dda3b492b125e/maintainability\n[version]: https://badge.fury.io/rb/stockpile_cache\n[version-image]: https://badge.fury.io/rb/stockpile_cache.svg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkit%2Fstockpile_cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkit%2Fstockpile_cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkit%2Fstockpile_cache/lists"}