snerdmq 0.3.2 → 0.3.3

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 +68 -9
  3. data/snerdmq.gemspec +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1d73035fba1f4d5bd42c382bc5c8798db8597ddbbe2829cf6fd9323747751e7
4
- data.tar.gz: 42b2633c35e968f1640a603b4d4ab59de9cdf7257f9b045c53af7cd97ba68c21
3
+ metadata.gz: 85e9f934b6976cdbd8c95718707762e2da87e93ea53448a51b3983b40d145f26
4
+ data.tar.gz: 82d99ccce4066f516da45f536e36f8539d569cdf47d1a74442b1557086830243
5
5
  SHA512:
6
- metadata.gz: 11a0de6095c802f2a6aa85d0ca5ce4af45b5be5f8763212e10f74608b9ff3a79cdc71929e5937ee8961076f9094124f19321ac9bf9ae78b42133ba86ffbffcbc
7
- data.tar.gz: ba85ccfeff123d455ea3694709ca2a7825ab535fc70b6963d29c6d6486a9126b38f0b2d868afd5d0e05964dc9d143fa7a8b9efb3499f7b79e0df383f3f945b0b
6
+ metadata.gz: b18cee9ae796c2c612d44bea8c6aa0e81725e4a27f7f4001bb4c1d66acafc89ea2766c21e573dedebf45a8689b4b2a60abc885ad0d13a632de4da3d9934e2d5c
7
+ data.tar.gz: 815dc8ba1eb2977aba024af95fba389753a0428d3483c3db438e8ced86fada4666c0375d7d6d4b032a3705ac2f8c9fe30aea5c82d9967adc1260c17cfcf53d86
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
  <img src="./assets/Designer-9.png" height="120" alt="SnerdMQ Ruby Logo" />
3
- <h1>💎 SnerdMQ Ruby SDK v0.3.2</h1>
3
+ <h1>💎 SnerdMQ Ruby SDK v0.3.3</h1>
4
4
  <p>A zero-config, C-speed background job queue for Ruby. Ditch Redis and Sidekiq for lightweight, persistent background jobs.</p>
5
5
 
6
6
  [![Gem Version](https://badge.fury.io/rb/snerdmq.svg)](https://badge.fury.io/rb/snerdmq)
@@ -9,7 +9,7 @@
9
9
 
10
10
  This is the official Ruby SDK wrapper for **SnerdMQ**. It handles all JSON-RPC communication and `IO.popen` orchestration so you can write lightning-fast background jobs without managing any external databases like Redis or Postgres.
11
11
 
12
- ## ✨ v0.3.2 AI Features
12
+ ## ✨ v0.3.3 AI Features
13
13
  - **Smart API Rate-Limiting**: Natively tracks `rate_limit_group` execution velocity to prevent 429 "Too Many Requests" API errors.
14
14
  - **Payload-Hashing Deduplication**: Automatically computes cryptographic hashes to drop duplicate tasks instantly.
15
15
  - **Dynamic Float Prioritization**: A native Binary Max-Heap bypasses standard FIFO rules for high urgency tasks.
@@ -18,7 +18,7 @@ This is the official Ruby SDK wrapper for **SnerdMQ**. It handles all JSON-RPC c
18
18
  - **Zero Rust Required**: Our gem installation script automatically downloads the pre-compiled C-speed Rust binary for your OS.
19
19
  - **Thread Safe**: Uses native Ruby `Thread`s and `Mutex` locks to orchestrate I/O without blocking your main event loop.
20
20
 
21
- ### ⚙️ Advanced Task Configuration (v0.3.2)
21
+ ### ⚙️ Advanced Task Configuration (v0.3.3)
22
22
  To power complex AI workflows, tasks can now be configured with advanced orchestration parameters:
23
23
 
24
24
  * **`auto_dedupe` (`true/false`)**: If set to `true`, the daemon computes a cryptographic hash of the `task_type` and `data`. If an identical payload is currently sitting in the queue pending execution, this new task is silently dropped. Excellent for preventing duplicate generative AI requests from trigger-happy users!
@@ -167,18 +167,77 @@ end
167
167
 
168
168
  ---
169
169
 
170
- ## 🌍 Advanced: Distributed Scaling
170
+ ## 🧩 Queue Topology: One Queue or Many?
171
+
172
+ ### ✅ Recommended: one queue, all job types (singleton)
173
+
174
+ Each `Snerdmq::SnerdQueue` client spawns its own Rust daemon and **exclusively owns** its storage directory (`.snerdata` by default). The recommended pattern is **one client per application process**: register every job type on it and serve a single shared dashboard:
175
+
176
+ ```ruby
177
+ require 'snerdmq'
178
+
179
+ # ONE queue client for the whole app
180
+ queue = Snerdmq::SnerdQueue.new
181
+
182
+ # Job type #1: image processing
183
+ queue.register_handler("process_image") do |data|
184
+ puts "Processing image: #{data['image_id']}"
185
+ end
186
+
187
+ # Job type #2: OTP emails — same queue, same daemon
188
+ queue.register_handler("send_otp_email") do |data|
189
+ puts "Sending OTP to: #{data['to']}"
190
+ end
191
+
192
+ queue.start_listening
193
+
194
+ # Both job types flow through the exact same queue
195
+ queue.enqueue(task_id: "img-1", task_type: "process_image", data: { "image_id" => "abc123" }, max_retries: 3, retry_after_hours: 0.5)
196
+ queue.enqueue(task_id: "otp-1", task_type: "send_otp_email", data: { "to" => "john@wick.com" }, max_retries: 3, retry_after_hours: 0.5)
197
+
198
+ # ONE dashboard shows every job type
199
+ queue.start_dashboard(port: 8080)
200
+ ```
171
201
 
172
- By default, the SDK spins up the Rust daemon which writes the queue to a local file (`.snerdata/tasks/tasks.log`).
202
+ All job types share everything: the same persistent job log, retry/DLQ pipeline, rate-limit state, stats and one dashboard at `http://localhost:8080` showing all of them.
173
203
 
174
- If you have multiple Ruby microservices (or Rails instances) running behind a load balancer and want them to share the exact same queue, simply mount a **Shared Network Drive** (like AWS EFS or NFS) to all of your servers and pass the shared path:
204
+ ### 🚫 Same storage twice = fails fast
205
+
206
+ The daemon takes an **exclusive OS-level lock** on its storage directory at startup. A second client on the same storage fails instead of silently double-executing your jobs:
207
+
208
+ ```ruby
209
+ first = Snerdmq::SnerdQueue.new # ✅ owns .snerdata
210
+ second = Snerdmq::SnerdQueue.new # ❌ daemon refuses to start:
211
+ # "Another daemon is already running on storage '.snerdata'"
212
+ ```
213
+
214
+ This applies across processes too — with **Puma/Unicorn clustered workers, every worker is a separate process** that spawns its own daemon, so each worker needs its own `storage_path` (or run a single dedicated worker process for jobs).
215
+
216
+ ### 🔀 Need multiple queues? Give each one its own storage
217
+
218
+ ```ruby
219
+ images = Snerdmq::SnerdQueue.new(storage_path: ".snerdata-images")
220
+ emails = Snerdmq::SnerdQueue.new(storage_path: ".snerdata-emails")
221
+
222
+ images.start_dashboard(port: 8080) # separate dashboards, so separate ports
223
+ emails.start_dashboard(port: 8081)
224
+ ```
225
+
226
+ Now you have two fully independent engines: separate job logs, separate rate-limit state, separate dashboards. Only split when you actually need isolation (different teams, different retention, independent monitoring) — otherwise the singleton is simpler and recommended.
227
+
228
+ ---
229
+
230
+ ## 🌍 Advanced: Distributed Scaling
231
+
232
+ Because the daemon exclusively locks its storage directory, scaling horizontally means **one queue per server**, each with its own storage. Your load balancer routes requests across servers, and every server processes the jobs it enqueued:
175
233
 
176
234
  ```ruby
177
235
  require 'snerdmq'
178
236
 
179
- # All of your Ruby servers point to the exact same shared file!
180
- # SnerdMQ's native OS file-locking guarantees zero data corruption.
181
- queue = Snerdmq::SnerdQueue.new(storage_path: "/mnt/aws-efs-shared-drive/snerd_tasks.log")
237
+ # Each server runs its own daemon on its own storage dir (local disk works fine)
238
+ queue = Snerdmq::SnerdQueue.new(storage_path: "/var/data/snerd") # per-server storage
182
239
  ```
183
240
 
241
+ A shared network drive (AWS EFS or NFS) is still a good home for that storage when a single instance needs durable state — e.g. a container that restarts but must keep its queue. Native OS file locking (`flock`) keeps writes safe — no Redis required.
242
+
184
243
  *Built with ❤️ for John Wick tier engineering.*
data/snerdmq.gemspec CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "snerdmq"
6
- spec.version = "0.3.2"
6
+ spec.version = "0.3.3"
7
7
  spec.authors = ["Greyhands2"]
8
8
  spec.email = ["developer@example.com"]
9
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snerdmq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greyhands2
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-18 00:00:00.000000000 Z
11
+ date: 2026-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack