{"id":30577651,"url":"https://github.com/kiebor81/mudis","last_synced_at":"2025-10-08T17:10:13.665Z","repository":{"id":304893155,"uuid":"1020439042","full_name":"kiebor81/mudis","owner":"kiebor81","description":"Mudis is a fast, thread-safe, in-memory, sharded LRU cache for Ruby and Ruby-on-Rails applications. ","archived":false,"fork":false,"pushed_at":"2025-07-21T06:48:08.000Z","size":1111,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-29T05:35:40.692Z","etag":null,"topics":["cache","cache-control","cache-storage","caching","expiry","in-memory","in-process","key-value-store","least-recently-used","lock-free","lru","lru-cache","lru-eviction","memory-sharding","rails","ruby","ruby-gem","thread-safe","ttl-cache","ttl-cache-implementation"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/kiebor81.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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,"zenodo":null}},"created_at":"2025-07-15T21:50:12.000Z","updated_at":"2025-08-02T18:30:46.000Z","dependencies_parsed_at":"2025-07-17T04:17:31.391Z","dependency_job_id":"ca0973aa-08b7-4713-a332-dd8e86319a9f","html_url":"https://github.com/kiebor81/mudis","commit_stats":null,"previous_names":["kiebor81/mudis"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kiebor81/mudis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiebor81%2Fmudis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiebor81%2Fmudis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiebor81%2Fmudis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiebor81%2Fmudis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kiebor81","download_url":"https://codeload.github.com/kiebor81/mudis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiebor81%2Fmudis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278254466,"owners_count":25956604,"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-10-04T02:00:05.491Z","response_time":63,"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-control","cache-storage","caching","expiry","in-memory","in-process","key-value-store","least-recently-used","lock-free","lru","lru-cache","lru-eviction","memory-sharding","rails","ruby","ruby-gem","thread-safe","ttl-cache","ttl-cache-implementation"],"created_at":"2025-08-29T02:41:33.904Z","updated_at":"2025-10-08T17:10:13.649Z","avatar_url":"https://github.com/kiebor81.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"![mudis_signet](design/mudis.png \"Mudis\")\n\n[![Gem Version](https://badge.fury.io/rb/mudis.svg?icon=si%3Arubygems\u0026refresh=1\u0026cachebust=0)](https://badge.fury.io/rb/mudis)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n**Mudis** is a fast, thread-safe, in-memory, sharded LRU (Least Recently Used) cache for Ruby applications. Inspired by Redis, it provides value serialization, optional compression, per-key expiry, and metric tracking in a lightweight, dependency-free package that lives inside your Ruby process.\n\nIt’s ideal for scenarios where performance and process-local caching are critical, and where a full Redis setup is overkill or otherwise not possible/desirable.\n\nAlternatively, Mudis can be upscaled with higher sharding and resources in a dedicated Rails app to provide a [Mudis server](#create-a-mudis-server).\n\n### Why another Caching Gem?\n\nThere are plenty out there, in various states of maintenance and in many shapes and sizes. So why on earth do we need another? I needed a drop-in replacement for Kredis, and the reason I was interested in using Kredis was for the simplified API and keyed management it gave me in extension to Redis. But what I didn't really need was Redis. I needed an observable, fast, simple, easy to use, flexible and highly configurable, thread-safe and high performant caching system which didn't require too many dependencies or standing up additional services. So, Mudis was born. In its most rudimentary state it was extremely useful in my project, which was an API gateway connecting into mutliple micro-services and a wide selection of APIs. The majority of the data was cold and produced by repeat expensive queries across several domains. Mudis allowed for me to minimize the footprint of the gateway, and improve end user experience, and increase performance. So, yeah, there's a lot of these gems out there, but none which really met all my needs. I decided to provide Mudis for anyone else. If you use it, I'd be interested to know how and whether you got any benefit.\n\n#### Similar Gems\n\n- [FastCache](https://github.com/swoop-inc/fast_cache)\n- [EasyCache](https://github.com/malvads/easycache)\n- [MiniCache](https://github.com/derrickreimer/mini_cache)\n- [Zache](https://github.com/yegor256/zache)\n\n#### Feature / Function Comparison\n\n| **Feature**                            | **Mudis** | **MemoryStore** (`Rails.cache`) | **FastCache**  | **Zache**     | **EasyCache** | **MiniCache**  |\n| -------------------------------------- | ---------------- | ------------------------------- | -------------- | ------------- | ------------- | -------------- |\n| **LRU eviction strategy**              | ✅ Per-bucket     | ✅ Global                        | ✅ Global       | ❌             | ❌             | ✅ Simplistic   |\n| **TTL expiry support**                 | ✅                | ✅                               | ✅              | ✅             | ✅             | ✅              |\n| **Background expiry cleanup thread**   | ✅                | ❌ (only on access)              | ❌              | ✅            | ❌             | ❌              |\n| **Thread safety**                      | ✅ Bucketed       | ⚠️ Global lock                  | ✅ Fine-grained | ✅    | ⚠️     | ⚠️      |\n| **Sharding (buckets)**                 | ✅                | ❌                               | ✅              | ❌             | ❌             | ❌              |\n| **Custom serializers**                 | ✅                | ✅                               | ❌              | ❌             | ❌             | ❌              |\n| **Compression (Zlib)**                 | ✅                | ✅                               | ❌              | ❌             | ❌             | ❌              |\n| **Hard memory cap**                    | ✅                | ❌                               | ❌              | ❌             | ❌             | ❌              |\n| **Max value size enforcement**         | ✅                | ❌                               | ❌              | ❌             | ❌             | ❌              |\n| **Metrics (hits, misses, evictions)**  | ✅                | ⚠️ Partial                      | ❌              | ❌             | ❌             | ❌              |\n| **Fetch/update pattern**               | ✅ Full           | ✅ Standard                      | ⚠️ Partial     | ✅ Basic       | ✅ Basic       | ✅ Basic        |\n| **Namespacing**                        | ✅                | ✅                               | ❌              | ❌             | ❌             | ❌              |\n| **Replace (if exists)**                | ✅                | ✅                               | ❌              | ❌             | ❌             | ❌              |\n| **Clear/delete method**                | ✅                | ✅                               | ✅              | ✅             | ✅             | ✅              |\n| **Key inspection with metadata**       | ✅                | ❌                               | ❌              | ❌             | ❌             | ❌              |\n| **Concurrency model**                  | ✅                | ❌                               | ✅              | ❌             | ❌             | ❌              |\n| **Maintenance level**                  | ✅                | ✅                               | ✅              | ⚠️            | ⚠️            | ⚠️             |\n| **Suitable for APIs or microservices** | ✅                | ⚠️ Limited                      | ✅              | ⚠️ Small apps | ⚠️ Small apps | ❌ |\n\n---\n\n## Design\n\n#### Internal Structure and Behaviour\n\n![mudis_flow](design/mudis_obj.png \"Mudis Internals\")\n\n#### Write - Read - Eviction\n\n![mudis_flow](design/mudis_flow.png \"Write - Read - Eviction\")\n\n#### Cache Key Lifecycle\n\n![mudis_lru](design/mudis_lru.png \"Mudis Cache Key Lifecycle\")\n\n---\n\n## Features\n\n- **Thread-safe**: Uses per-bucket mutexes for high concurrency.\n- **Sharded**: Buckets data across multiple internal stores to minimize lock contention.\n- **LRU Eviction**: Automatically evicts least recently used items as memory fills up.\n- **Expiry Support**: Optional TTL per key with background cleanup thread.\n- **Compression**: Optional Zlib compression for large values.\n- **Metrics**: Tracks hits, misses, and evictions.\n\n---\n\n## Installation\n\nAdd this line to your Gemfile:\n\n```ruby\ngem 'mudis'\n```\n\nOr install it manually:\n\n```bash\ngem install mudis\n```\n\n---\n\n## Configuration (Rails)\n\nIn your Rails app, create an initializer:\n\n```ruby\n# config/initializers/mudis.rb\nMudis.configure do |c|\n  c.serializer = JSON        # or Marshal | Oj\n  c.compress = true          # Compress values using Zlib\n  c.max_value_bytes = 2_000_000  # Reject values \u003e 2MB\n  c.hard_memory_limit = true # enforce hard memory limits\n  c.max_bytes = 1_073_741_824 # set maximum cache size\nend\n\nMudis.start_expiry_thread(interval: 60) # Cleanup every 60s\n\nat_exit do\n  Mudis.stop_expiry_thread\nend\n```\n\nOr with direct setters:\n\n```ruby\nMudis.serializer = JSON        # or Marshal | Oj\nMudis.compress = true          # Compress values using Zlib\nMudis.max_value_bytes = 2_000_000  # Reject values \u003e 2MB\nMudis.hard_memory_limit = true # enforce hard memory limits\nMudis.max_bytes = 1_073_741_824 # set maximum cache size\n\nMudis.start_expiry_thread(interval: 60) # Cleanup every 60s\n\n## set at exit hook\n```\n\n---\n\n## Basic Usage\n\n```ruby\nrequire 'mudis'\n\n# Write a value with optional TTL\nMudis.write('user:123', { name: 'Alice' }, expires_in: 600)\n\n# Read it back\nMudis.read('user:123') # =\u003e { \"name\" =\u003e \"Alice\" }\n\n# Check if it exists\nMudis.exists?('user:123') # =\u003e true\n\n# Atomically update\nMudis.update('user:123') { |data| data.merge(age: 30) }\n\n# Delete a key\nMudis.delete('user:123')\n```\n\n### Developer Utilities\n\nMudis provides utility methods to help with test environments, console debugging, and dev tool resets.\n\n#### `Mudis.reset!`\nClears the internal cache state. Including all keys, memory tracking, and metrics. Also stops the expiry thread.\n\n```ruby\nMudis.write(\"foo\", \"bar\")\nMudis.reset!\nMudis.read(\"foo\") # =\u003e nil\n```\n\n- Wipe all buckets (@stores, @lru_nodes, @current_bytes)\n- Reset all metrics (:hits, :misses, :evictions, :rejected)\n- Stop any running background expiry thread\n\n#### `Mudis.reset_metrics!`\n\nClears only the metric counters and preserves all cached values.\n\n```ruby\nMudis.write(\"key\", \"value\")\nMudis.read(\"key\")    # =\u003e \"value\"\nMudis.metrics        # =\u003e { hits: 1, misses: 0, ... }\n\nMudis.reset_metrics!\nMudis.metrics        # =\u003e { hits: 0, misses: 0, ... }\nMudis.read(\"key\")    # =\u003e \"value\" (still cached)\n```\n\n#### `Mudis.least_touched`\n\nReturns the top `n` (or all) keys that have been read the fewest number of times, across all buckets. This is useful for identifying low-value cache entries that may be safe to remove or exclude from caching altogether.\n\nEach result includes the full key and its access count.\n\n```ruby\nMudis.least_touched\n# =\u003e [[\"foo\", 0], [\"user:42\", 1], [\"product:123\", 2], ...]\n\nMudis.least_touched(5)\n# =\u003e returns top 5 least accessed keys\n```\n\n#### `Mudis.keys(namespace:)`\n\nReturns all keys for a given namespace.\n\n```ruby\nMudis.write(\"u1\", \"alpha\", namespace: \"users\")\nMudis.write(\"u2\", \"beta\", namespace: \"users\")\n\nMudis.keys(namespace: \"users\")\n# =\u003e [\"u1\", \"u2\"]\n\n```\n\n#### `Mudis.clear_namespace(namespace:)`\n\nDeletes all keys within a namespace.\n\n```ruby\nMudis.clear_namespace(\"users\")\nMudis.read(\"u1\", namespace: \"users\") # =\u003e nil\n```\n\n---\n\n## Rails Service Integration\n\nFor simplified or transient use in a controller, you can wrap your cache logic in a reusable thin class:\n\n```ruby\nclass MudisService\n  attr_reader :cache_key, :namespace\n\n  # Initialize the service with a cache key and optional namespace\n  #\n  # @param cache_key [String] the base key to use\n  # @param namespace [String, nil] optional logical namespace\n  def initialize(cache_key, namespace: nil)\n    @cache_key = cache_key\n    @namespace = namespace\n  end\n\n  # Write a value to the cache\n  #\n  # @param data [Object] the value to cache\n  # @param expires_in [Integer, nil] optional TTL in seconds\n  def write(data, expires_in: nil)\n    Mudis.write(cache_key, data, expires_in: expires_in, namespace: namespace)\n  end\n\n  # Read the cached value or return default\n  #\n  # @param default [Object] fallback value if key is not present\n  def read(default: nil)\n    Mudis.read(cache_key, namespace: namespace) || default\n  end\n\n  # Update the cached value using a block\n  #\n  # @yieldparam current [Object] the current value\n  # @yieldreturn [Object] the updated value\n  def update\n    Mudis.update(cache_key, namespace: namespace) { |current| yield(current) }\n  end\n\n  # Delete the key from cache\n  def delete\n    Mudis.delete(cache_key, namespace: namespace)\n  end\n\n  # Return true if the key exists in cache\n  def exists?\n    Mudis.exists?(cache_key, namespace: namespace)\n  end\n\n  # Fetch from cache or compute and store it\n  #\n  # @param expires_in [Integer, nil] optional TTL\n  # @param force [Boolean] force recomputation\n  # @yield return value if key is missing\n  def fetch(expires_in: nil, force: false)\n    Mudis.fetch(cache_key, expires_in: expires_in, force: force, namespace: namespace) do\n      yield\n    end\n  end\n\n  # Inspect metadata for the current key\n  #\n  # @return [Hash, nil] metadata including :expires_at, :created_at, :size_bytes, etc.\n  def inspect_meta\n    Mudis.inspect(cache_key, namespace: namespace)\n  end\nend\n\n```\n\nUse it like:\n\n```ruby\ncache = MudisService.new(\"user:42:profile\", namespace: \"users\")\n\ncache.write({ name: \"Alice\" }, expires_in: 300)\ncache.read                       # =\u003e { \"name\" =\u003e \"Alice\" }\ncache.exists?                    # =\u003e true\n\ncache.update { |data| data.merge(age: 30) }\ncache.fetch(expires_in: 60) { expensive_query }\ncache.inspect_meta               # =\u003e { key: \"users:user:42:profile\", ... }\n```\n\n---\n\n## Metrics\n\nTrack cache effectiveness and performance:\n\n```ruby\nMudis.metrics\n# =\u003e {\n#   hits: 15,\n#   misses: 5,\n#   evictions: 3,\n#   rejected: 0,\n#   total_memory: 45678,\n#   least_touched: [\n#     [\"user:1\", 0],\n#     [\"post:5\", 1],\n#     ...\n#   ],\n#   buckets: [\n#     { index: 0, keys: 12, memory_bytes: 12345, lru_size: 12 },\n#     ...\n#   ]\n# }\n\n```\n\nOptionally, return these metrics from a controller for remote analysis and monitoring if using Rails.\n\n```ruby\nclass MudisController \u003c ApplicationController\n  def metrics\n    render json: { mudis: Mudis.metrics }\n  end\n\nend\n```\n\n---\n\n## Advanced Configuration\n\n| Setting                  | Description                                 | Default            |\n|--------------------------|---------------------------------------------|--------------------|\n| `Mudis.serializer`       | JSON, Marshal, or Oj                        | `JSON`             |\n| `Mudis.compress`         | Enable Zlib compression                     | `false`            |\n| `Mudis.max_value_bytes`  | Max allowed size in bytes for a value       | `nil` (no limit)   |\n| `Mudis.buckets`          | Number of cache shards        | `32`               |\n| `Mudis.start_expiry_thread`    | Background TTL cleanup loop (every N sec)   | Disabled by default|\n| `Mudis.hard_memory_limit`    | Enforce hard memory limits on key size and reject if exceeded  | `false`|\n| `Mudis.max_bytes`    | Maximum allowed cache size  | `1GB`|\n| `Mudis.max_ttl`    | Set the maximum permitted TTL  | `nil` (no limit) |\n| `Mudis.default_ttl`    | Set the default TTL for fallback when none is provided  | `nil` |\n\nBuckets can also be set using a `MUDIS_BUCKETS` environment variable.\n\nWhen setting `serializer`, be mindful of the below\n\n| Serializer | Recommended for                       |\n| ---------- | ------------------------------------- |\n| `Marshal`  | Ruby-only apps, speed-sensitive logic |\n| `JSON`     | Cross-language interoperability       |\n| `Oj`       | API-heavy apps using JSON at scale    |\n\n---\n\n## Benchmarks\n\n#### Serializer(s)\n\n_100000 iterations_\n\n| Serializer     | Total Time (s) | Ops/sec |\n|----------------|------------|----------------|\n| oj         | 0.1342         | 745320  |\n| marshal        | 0.3228         | 309824  |\n| json           | 0.9035         | 110682  |\n| oj + zlib    | 1.8050         | 55401   |\n| marshal + zlib   | 1.8057         | 55381   |\n| json + zlib      | 2.7949         | 35780   |\n\n\u003e If opting for OJ, you will need to install the dependency in your project and configure as needed.\n\n#### Mudis vs Rails.cache\n\nMudis is marginally slower than `Rails.cache` by design; it trades raw speed for control, observability, and safety.\n\n_10000 iterations of 1MB, Marshal (to match MemoryStore default), compression ON_\n\n| Operation | `Rails.cache` | `Mudis`     | Delta     |\n| --------- | ------------- | ----------- | --------- |\n| Write     | 2.139 ms/op   | 2.417 ms/op | +0.278 ms |\n| Read      | 0.007 ms/op   | 0.810 ms/op | +0.803 ms |\n\n\u003e For context: a typical database query or HTTP call takes 10–50ms. A difference of less than 1ms per operation is negligible for most apps.\n\n#### **Why this overhead exists**\n\nMudis includes features that MemoryStore doesn’t:\n\n| Feature            | Mudis                  | Rails.cache (MemoryStore)   |\n| ------------------ | ---------------------- | --------------------------- |\n| Per-key TTL expiry | ✅    | ⚠️ on access |\n| True LRU eviction  | ✅     | ❌          |\n| Hard memory limits | ✅                   | ❌         |\n| Value compression  | ✅     | ❌             |\n| Thread safety      | ✅ Bucket-level mutexes | ✅ Global mutex              |\n| Observability      | ✅         | ❌           |\n| Namespacing        | ✅           | ❌ Manual scoping        |\n\nIt will be down to the developer to decide if a fraction of a millisecond is worth\n\n- Predictable eviction\n- Configurable expiry\n- Memory protection\n- Namespace scoping\n- Real-time metrics for hits, misses, evictions, memory usage\n\n_10000 iterations of 1MB, Marshal (to match MemoryStore default), compression OFF (to match MemoryStore default)_\n\n| Operation | `Rails.cache` | `Mudis`     | Delta         |\n| --------- | ------------- | ----------- | ------------- |\n| Write     | 2.342 ms/op   | 0.501 ms/op | **−1.841 ms** |\n| Read      | 0.007 ms/op   | 0.011 ms/op | +0.004 ms     |\n\nWith compression disabled, Mudis writes significanty faster and reads are virtually identical. Optimisation and configuration of Mudis will be determined by your individual needs.\n\n#### Other Benchmarks\n\n_10000 iterations of 512KB, JSON, compression OFF (to match MemoryStore default)_\n\n| Operation | `Rails.cache` | `Mudis`     | Delta         |\n| --------- | ------------- | ----------- | ------------- |\n| Write     | 1.291 ms/op   | 0.32 ms/op | **−0.971 ms** |\n| Read      | 0.011 ms/op   | 0.048 ms/op | +0.037 ms     |\n\n_10000 iterations of 512KB, JSON, compression ON_\n\n| Operation | `Rails.cache` | `Mudis`     | Delta         |\n| --------- | ------------- | ----------- | ------------- |\n| Write     | 1.11 ms/op   | 1.16 ms/op |  +0.05 ms |\n| Read      | 0.07 ms/op   | 0.563 ms/op | +0.493 ms     |\n\n---\n\n## Graceful Shutdown\n\nDon’t forget to stop the expiry thread when your app exits:\n\n```ruby\nat_exit { Mudis.stop_expiry_thread }\n```\n\n---\n\n## Known Limitations\n\n- Data is **non-persistent**.\n- Compression introduces CPU overhead.\n\n---\n\n## Create a Mudis Server\n\n### Minimal Setup\n\n- Create a new Rails API app:\n\n```bash\nrails new mudis-server --api\ncd mudis-server\n```\n\n- Add mudis to your Gemfile\n- Create Initializer: `config/initializers/mudis.rb`\n- Define routes\n\n```ruby\nRails.application.routes.draw do\n  get \"/cache/:key\", to: \"cache#show\"\n  post \"/cache/:key\", to: \"cache#write\"\n  delete \"/cache/:key\", to: \"cache#delete\"\n  get \"/metrics\", to: \"cache#metrics\"\nend\n```\n\n- Create a `cache_controller` (with optional per caller/consumer namespace)\n\n```ruby\nclass CacheController \u003c ApplicationController\n\n  def show\n    key = params[:key]\n    ns  = params[:namespace]\n\n    value = Mudis.read(key, namespace: ns)\n    if value.nil?\n      render json: { error: \"not found\" }, status: :not_found\n    else\n      render json: { value: value }\n    end\n  end\n\n  def write\n    key = params[:key]\n    ns  = params[:namespace]\n    val = params[:value]\n    ttl = params[:expires_in]\u0026.to_i\n\n    Mudis.write(key, val, expires_in: ttl, namespace: ns)\n    render json: { status: \"written\", key: key }\n  end\n\n  def delete\n    key = params[:key]\n    ns  = params[:namespace]\n\n    Mudis.delete(key, namespace: ns)\n    render json: { status: \"deleted\" }\n  end\n\n  def metrics\n    render json: Mudis.metrics\n  end\nend\n```\n\n- Test it\n\n```bash\ncurl http://localhost:3000/cache/foo\ncurl -X POST http://localhost:3000/cache/foo -d 'value=bar\u0026expires_in=60'\ncurl http://localhost:3000/metrics\n\n# Write with namespace\ncurl -X POST \"http://localhost:3000/cache/foo?namespace=orders\" \\\n     -d \"value=123\u0026expires_in=60\"\n\n# Read from namespace\ncurl \"http://localhost:3000/cache/foo?namespace=orders\"\n\n# Delete from namespace\ncurl -X DELETE \"http://localhost:3000/cache/foo?namespace=orders\"\n\n```\n\n---\n\n## Project Philosophy\n\nMudis is intended to be a minimal, thread-safe, in-memory cache designed specifically for Ruby applications. It focuses on:\n\n- In-process caching\n- Fine-grained memory and namespace control\n- Observability and testing friendliness\n- Minimal external dependencies\n- Configurability without complexity\n\nThe primary use cases are:\n\n- Per-service application caches\n- Short-lived local caching inside background jobs or API layers\n\nMudis is not intended to be a general-purpose, distributed caching platform. You are, however, welcome to build on top of Mudis if you want its functionality in such projects. E.g.,\n\n- mudis-server – expose Mudis via HTTP, web sockets, hooks, etc\n- mudis-broker – distributed key routing layer for coordinating multiple Mudis nodes\n- mudis-activejob-store – adapter for using Mudis in job queues or retry buffers\n\n---\n\n## Roadmap\n\n#### API Enhancements\n\n- [x] bulk_read(keys, namespace:): Batch retrieval of multiple keys with a single method call\n\n#### Safety \u0026 Policy Controls\n\n- [x] max_ttl: Enforce a global upper bound on expires_in to prevent excessively long-lived keys\n- [x] default_ttl: Provide a fallback TTL when one is not specified\n\n#### Debugging\n\n- [x] clear_namespace(namespace): Remove all keys in a namespace in one call\n\n#### Refactor Mudis \n\n- [ ] Review Mudis for improved readability and reduce complexity in top-level functions\n- [ ] Enhanced guards\n- [ ] Review for functionality gaps and enhance as needed \n\n---\n\n## License\n\nMIT License © kiebor81\n\n---\n\n## Contributing\n\nSee [contributor's guide](CONTRIBUTING.md)\n\n---\n\n## Contact\n\nFor issues, suggestions, or feedback, please open a GitHub issue\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiebor81%2Fmudis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkiebor81%2Fmudis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiebor81%2Fmudis/lists"}