mudis 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +174 -25
  3. data/lib/mudis/version.rb +1 -1
  4. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a4a27b63d070e4a8e356d6ffed09eda290c7f633ffb3bf7b9008499170b4a55
4
- data.tar.gz: 1ccaf9415f6e595272884c926615861975f376d5a52c7109a845dcb4b4480e8d
3
+ metadata.gz: b180000138c976ee0e0c7a7cdc068550c5f33f39f363c63ba6397b84fe8f6cbe
4
+ data.tar.gz: ee6de323fd9dcc5914ec0fde68da5fff7289e6c830395b9d4be4271d389b2c15
5
5
  SHA512:
6
- metadata.gz: 2fbcea123de9db1aefcb31e8aea21069bbbdae11300b3a6dd2b73b65c801c6b9dbdc5f60d5d84e001e26059a2e6a2e1e1ef01b61e23261f143cbf0ae3c129e40
7
- data.tar.gz: 3344818c66b36d4fbb9c5e5e287a3067ee7a8c6779b2803084b8b7d4001337e073ccd45406665f2e50bc27ef58ac0e4bc9a17168f85fb302e2b0331cbc11ba2c
6
+ metadata.gz: e7d2c14ca2b2dce8ed23f5fb371fe73456d92d9613e25d75fb645d1a6903259a21dd31dc7e3acca8f4336dc77990d5f33fce9254e3becdbcc59d7c19c526a302
7
+ data.tar.gz: 6619380f6d7206caec28c0e1f3f5450bb8991817fff6c08d6e7b5ceff2c82edc8a7c7b51b38894e5fb5a09e5f41a0546c50b951d088accfc1dc70a91935d398d
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  ![mudis_signet](design/mudis.png "Mudis")
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/mudis.svg?icon=si%3Arubygems&refresh=1)](https://badge.fury.io/rb/mudis)
3
+ [![Gem Version](https://badge.fury.io/rb/mudis.svg?icon=si%3Arubygems&refresh=1&cachebust=0)](https://badge.fury.io/rb/mudis)
4
4
 
5
5
  **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.
6
6
 
7
7
  It’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.
8
8
 
9
- Alternatively, Mudis can be upscaled with higher sharding and resources in a dedicated Rails app to provide a Mudis server.
9
+ Alternatively, Mudis can be upscaled with higher sharding and resources in a dedicated Rails app to provide a [Mudis server](#create-a-mudis-server).
10
10
 
11
11
  ### Why another Caching Gem?
12
12
 
@@ -305,11 +305,10 @@ end
305
305
  | `Mudis.serializer` | JSON, Marshal, or Oj | `JSON` |
306
306
  | `Mudis.compress` | Enable Zlib compression | `false` |
307
307
  | `Mudis.max_value_bytes` | Max allowed size in bytes for a value | `nil` (no limit) |
308
- | `Mudis.buckets` | Number of cache shards (via ENV var) | `32` |
309
- | `start_expiry_thread` | Background TTL cleanup loop (every N sec) | Disabled by default|
310
- | `hard_memory_limit` | Enforce hard memory limits on key size and reject if exceeded | `false`|
311
- | `max_bytes` | Maximum allowed cache size | `1GB`|
312
- | `buckets` | Number of memory buckets (shards) | `32` |
308
+ | `Mudis.buckets` | Number of cache shards | `32` |
309
+ | `Mudis.start_expiry_thread` | Background TTL cleanup loop (every N sec) | Disabled by default|
310
+ | `Mudis.hard_memory_limit` | Enforce hard memory limits on key size and reject if exceeded | `false`|
311
+ | `Mudis.max_bytes` | Maximum allowed cache size | `1GB`|
313
312
 
314
313
  Buckets can also be set using a `MUDIS_BUCKETS` environment variable.
315
314
 
@@ -321,21 +320,69 @@ When setting `serializer`, be mindful of the below
321
320
  | `JSON` | Cross-language interoperability |
322
321
  | `Oj` | API-heavy apps using JSON at scale |
323
322
 
324
- #### Benchmarks
323
+ ---
324
+
325
+ ## Benchmarks
326
+
327
+ #### Serializer(s)
325
328
 
326
- Based on 100000 iterations
329
+ _100000 iterations_
327
330
 
328
- | Serializer | Iterations | Total Time (s) | Ops/sec |
329
- |----------------|------------|----------------|---------|
330
- | oj | 100000 | 0.1342 | 745320 |
331
- | marshal | 100000 | 0.3228 | 309824 |
332
- | json | 100000 | 0.9035 | 110682 |
333
- | oj + zlib | 100000 | 1.8050 | 55401 |
334
- | marshal + zlib | 100000 | 1.8057 | 55381 |
335
- | json + zlib | 100000 | 2.7949 | 35780 |
331
+ | Serializer | Total Time (s) | Ops/sec |
332
+ |----------------|------------|----------------|
333
+ | oj | 0.1342 | 745320 |
334
+ | marshal | 0.3228 | 309824 |
335
+ | json | 0.9035 | 110682 |
336
+ | oj + zlib | 1.8050 | 55401 |
337
+ | marshal + zlib | 1.8057 | 55381 |
338
+ | json + zlib | 2.7949 | 35780 |
336
339
 
337
340
  > If opting for OJ, you will need to install the dependency in your project and configure as needed.
338
341
 
342
+ #### Mudis vs Rails.cache
343
+
344
+ Mudis is marginally slower than `Rails.cache` by design; it trades raw speed for control, observability, and safety.
345
+
346
+ _10000 iterations of 1MB, Marshal (to match MemoryStore default), compression ON_
347
+
348
+ | Operation | `Rails.cache` | `Mudis` | Delta |
349
+ | --------- | ------------- | ----------- | --------- |
350
+ | Write | 2.139 ms/op | 2.417 ms/op | +0.278 ms |
351
+ | Read | 0.007 ms/op | 0.810 ms/op | +0.803 ms |
352
+
353
+ > 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.
354
+
355
+ ###### **Why this overhead exists**
356
+
357
+ Mudis includes features that MemoryStore doesn’t:
358
+
359
+ | Feature | Mudis | Rails.cache (MemoryStore) |
360
+ | ------------------ | ---------------------- | --------------------------- |
361
+ | Per-key TTL expiry | ✅ | ⚠️ on access |
362
+ | True LRU eviction | ✅ | ❌ |
363
+ | Hard memory limits | ✅ | ❌ |
364
+ | Value compression | ✅ | ❌ |
365
+ | Thread safety | ✅ Bucket-level mutexes | ✅ Global mutex |
366
+ | Observability | ✅ | ❌ |
367
+ | Namespacing | ✅ | ❌ Manual scoping |
368
+
369
+ It will be down to the developer to decide if a fraction of a millisecond is worth
370
+
371
+ - Predictable eviction
372
+ - Configurable expiry
373
+ - Memory protection
374
+ - Namespace scoping
375
+ - Real-time metrics for hits, misses, evictions, memory usage
376
+
377
+ _10000 iterations of 1MB, Marshal (to match MemoryStore default), compression OFF (to match MemoryStore default)_
378
+
379
+ | Operation | `Rails.cache` | `Mudis` | Delta |
380
+ | --------- | ------------- | ----------- | ------------- |
381
+ | Write | 2.342 ms/op | 0.501 ms/op | **−1.841 ms** |
382
+ | Read | 0.007 ms/op | 0.011 ms/op | +0.004 ms |
383
+
384
+ With compression disabled, Mudis writes significanty faster and reads are virtually identical. Optimisation and configuration of Mudis will be determined by your individual needs.
385
+
339
386
  ---
340
387
 
341
388
  ## Graceful Shutdown
@@ -355,6 +402,115 @@ at_exit { Mudis.stop_expiry_thread }
355
402
 
356
403
  ---
357
404
 
405
+ ## Create a Mudis Server
406
+
407
+ ### Minimal Setup
408
+
409
+ - Create a new Rails API app:
410
+
411
+ ```bash
412
+ rails new mudis-server --api
413
+ cd mudis-server
414
+ ```
415
+
416
+ - Add mudis to your Gemfile
417
+ - Create Initializer: `config/initializers/mudis.rb`
418
+ - Define routes
419
+
420
+ ```ruby
421
+ Rails.application.routes.draw do
422
+ get "/cache/:key", to: "cache#show"
423
+ post "/cache/:key", to: "cache#write"
424
+ delete "/cache/:key", to: "cache#delete"
425
+ get "/metrics", to: "cache#metrics"
426
+ end
427
+ ```
428
+
429
+ - Create a `cache_controller` (with optional per caller/consumer namespace)
430
+
431
+ ```ruby
432
+ class CacheController < ApplicationController
433
+
434
+ def show
435
+ key = params[:key]
436
+ ns = params[:namespace]
437
+
438
+ value = Mudis.read(key, namespace: ns)
439
+ if value.nil?
440
+ render json: { error: "not found" }, status: :not_found
441
+ else
442
+ render json: { value: value }
443
+ end
444
+ end
445
+
446
+ def write
447
+ key = params[:key]
448
+ ns = params[:namespace]
449
+ val = params[:value]
450
+ ttl = params[:expires_in]&.to_i
451
+
452
+ Mudis.write(key, val, expires_in: ttl, namespace: ns)
453
+ render json: { status: "written", key: key }
454
+ end
455
+
456
+ def delete
457
+ key = params[:key]
458
+ ns = params[:namespace]
459
+
460
+ Mudis.delete(key, namespace: ns)
461
+ render json: { status: "deleted" }
462
+ end
463
+
464
+ def metrics
465
+ render json: Mudis.metrics
466
+ end
467
+ end
468
+ ```
469
+
470
+ - Test it
471
+
472
+ ```bash
473
+ curl http://localhost:3000/cache/foo
474
+ curl -X POST http://localhost:3000/cache/foo -d 'value=bar&expires_in=60'
475
+ curl http://localhost:3000/metrics
476
+
477
+ # Write with namespace
478
+ curl -X POST "http://localhost:3000/cache/foo?namespace=orders" \
479
+ -d "value=123&expires_in=60"
480
+
481
+ # Read from namespace
482
+ curl "http://localhost:3000/cache/foo?namespace=orders"
483
+
484
+ # Delete from namespace
485
+ curl -X DELETE "http://localhost:3000/cache/foo?namespace=orders"
486
+
487
+ ```
488
+
489
+ ---
490
+
491
+ ## Project Philosophy
492
+
493
+ Mudis is intended to be a minimal, thread-safe, in-memory cache designed specifically for Ruby applications. It focuses on:
494
+
495
+ - In-process caching
496
+ - Fine-grained memory and namespace control
497
+ - Observability and testing friendliness
498
+ - Minimal external dependencies
499
+ - Configurability without complexity
500
+
501
+ The primary use cases are:
502
+
503
+ - Per-service application caches
504
+ - Short-lived local caching inside background jobs or API layers
505
+
506
+ Mudis 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.,
507
+
508
+ - mudis-server – expose Mudis via HTTP, web sockets, hooks, etc
509
+ - mudis-broker – distributed key routing layer for coordinating multiple Mudis nodes
510
+ - mudis-activejob-store – adapter for using Mudis in job queues or retry buffers
511
+
512
+ ---
513
+
358
514
  ## Roadmap
359
515
 
360
516
  #### API Enhancements
@@ -380,14 +536,7 @@ MIT License © kiebor81
380
536
 
381
537
  ## Contributing
382
538
 
383
- PRs are welcome! To get started:
384
-
385
- ```bash
386
- git clone https://github.com/kiebor81/mudis
387
- cd mudis
388
- bundle install
389
-
390
- ```
539
+ See [contributor's guide](CONTRIBUTING.md)
391
540
 
392
541
  ---
393
542
 
data/lib/mudis/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- MUDIS_VERSION = "0.4.3"
3
+ MUDIS_VERSION = "0.4.4"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mudis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - kiebor81
@@ -38,8 +38,9 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.12'
41
- description: Thread-safe, bucketed, in-process cache for Ruby apps. Drop-in replacement
42
- for Kredis in some scenarios.
41
+ description: Mudis is a fast, thread-safe, in-memory, sharded LRU cache for Ruby applications.
42
+ Inspired by Redis, it provides value serialization, optional compression, per-key
43
+ expiry, and metric tracking in a lightweight, dependency-free package.
43
44
  email:
44
45
  executables: []
45
46
  extensions: []
@@ -77,7 +78,8 @@ requirements: []
77
78
  rubygems_version: 3.5.17
78
79
  signing_key:
79
80
  specification_version: 4
80
- summary: A fast in-memory Ruby LRU cache with compression and expiry.
81
+ summary: A fast in-memory, thread-safe and high performance Ruby LRU cache with compression
82
+ and auto-expiry.
81
83
  test_files:
82
84
  - spec/guardrails_spec.rb
83
85
  - spec/mudis_spec.rb