zizq 0.3.5 → 0.3.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d7eb0e9668c055e6f5b6b8ec6aacb5c09f8df5eedcea038acdb14d164a58acf
4
- data.tar.gz: d30b95be8bab2eae5100b89fa7957278a20c301538e5630156bf9892739864a3
3
+ metadata.gz: a95c96d7b844064db29aea81935d6ec6e3c6953fc47459fcfd6253b6b44aa1e7
4
+ data.tar.gz: 19a8e38ef04716ba02b21bb4ce1f8f2b3e597b1f9845ada71dde5ae7d31fecd3
5
5
  SHA512:
6
- metadata.gz: dbe8d111b4083de907b4522ae4f0c110554a0ab5821a544d808c363868602178c15f983140436da6525b96ab30be159ac52309adfb05cb271739a7aee73174cc
7
- data.tar.gz: 39606af98c372c50147922ba7640dcd9e58d449c63927008abbcc03ac2b926e68d4856764152f51f16fb26554241e801df1fb862542e405a1087bd2213d4eaab
6
+ metadata.gz: d4158e9e2b3f58e2c1b823b26f8c81a9ee5ab347d72683377909fed7b4d0d163caf3e27708d3e1f3cbd1af3018068fda34d97405ec6095732b0cda57909a82fc
7
+ data.tar.gz: 95c1453a0af6a82e8ad0abd5e2a8085550ce4cf5ef6b2871cb653fdd1068994f69b36bb04a5e30d2ec76c1ccc02a1e142621a5c5bde7de9bab84517917b90fef
data/README.md CHANGED
@@ -12,7 +12,7 @@ API.
12
12
  ## Features
13
13
 
14
14
  * Multi-thread and/or multi-fiber concurrent worker (via [`async`](https://github.com/socketry/async))
15
- * `Zizq::Job` based job classes, Active Job support, or completely custom
15
+ * `Zizq::Job` based job classes, Active Job support, or low-level/custom
16
16
  * Enqueue and process jobs from one language to another
17
17
  * Arbitrary named queues
18
18
  * Granular job priorities
@@ -22,6 +22,7 @@ API.
22
22
  * Recurring jobs (cron)
23
23
  * Job introspection and management APIs, with support for `jq` query filters
24
24
  * Unique jobs
25
+ * Testing helpers
25
26
 
26
27
  ## Installation
27
28
 
@@ -32,13 +33,13 @@ API.
32
33
  Add it to your application's `Gemfile`:
33
34
 
34
35
  ```ruby
35
- gem 'zizq', '~> 0.3.5'
36
+ gem 'zizq', '~> 0.3.6'
36
37
  ```
37
38
 
38
39
  Or install it manually:
39
40
 
40
41
  ```shell
41
- $ gem install zizq -v 0.3.5
42
+ $ gem install zizq -v 0.3.6
42
43
  ```
43
44
 
44
45
  Ruby **3.2.8 or newer** is required. Client and server share version
@@ -62,7 +63,7 @@ Zizq.configure do |c|
62
63
  # Optional worker defaults — applied to every Zizq::Worker
63
64
  # instance and to runs of the `zizq-worker` executable. Explicit
64
65
  # kwargs or CLI flags override these.
65
- c.worker.queues = ['emails', 'payments']
66
+ c.worker.queues = ['emails', 'payments']
66
67
  c.worker.fiber_count = 25
67
68
  end
68
69
  ```
@@ -148,10 +149,42 @@ Zizq.enqueue_bulk do |b|
148
149
  end
149
150
  ```
150
151
 
151
- > [!NOTE]
152
- > Jobs can also be enqueued without `Zizq::Job` via `Zizq.enqueue_raw` —
153
- > designed for cross-language workflows where, for example, a Ruby app
154
- > enqueues jobs consumed by a Go service.
152
+ Jobs can also be enqueued without `Zizq::Job` via `Zizq.enqueue_raw` —
153
+ designed for lower-level code style, and for cross-language workflows where,
154
+ for example, a Ruby app enqueues jobs consumed by a Go service.
155
+
156
+ ```ruby
157
+ Zizq.enqueue_raw(
158
+ type: "send_email",
159
+ queue: "comms",
160
+ payload: { user_id: 42, template: "welcome" }
161
+ )
162
+ ```
163
+
164
+ ### Cross-language and low-level dispatch { #router }
165
+
166
+ When a Ruby app needs to *process* jobs enqueued by another language
167
+ (or by `Zizq.enqueue_raw`), `Zizq::Router` maps `type` strings to
168
+ handler blocks operating on plain JSON payloads:
169
+
170
+ ```ruby
171
+ Zizq.configure do |c|
172
+ c.dispatcher = Zizq::Router.new do
173
+ route('send_email') do |payload|
174
+ Mailer.deliver(payload['user_id'], payload['template'])
175
+ end
176
+
177
+ # Apps that mix the two styles can fall back to Zizq::Job
178
+ # for anything not handled by an explicit route.
179
+ fallback { |job| Zizq::Job.call(job) }
180
+ end
181
+ end
182
+ ```
183
+
184
+ See [Custom Dispatchers](https://zizq.io/docs/clients/ruby/dispatchers.html)
185
+ for full details. Dispatchers in Zizq are just objects that implement `#call`
186
+ with a single `Zizq::Resources::Job` argument, and `Zizq::Router` is just a
187
+ dispatcher itself.
155
188
 
156
189
  ### Running a worker
157
190
 
@@ -0,0 +1,100 @@
1
+ # Copyright (c) 2026 Chris Corbyn <chris@zizq.io>
2
+ # Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ # rbs_inline: enabled
5
+ # frozen_string_literal: true
6
+
7
+ module Zizq
8
+ # Dispatch jobs by `type` string, mapping each to a handler block.
9
+ #
10
+ # Designed for cross-language workflows: payloads are plain JSON
11
+ # values (Hashes / Arrays / strings / numbers), `type` is a String
12
+ # the producer agrees on with the consumer, and routes are
13
+ # registered explicitly — no `Zizq::Job` mixin involved.
14
+ #
15
+ # Zizq.configure do |c|
16
+ # c.dispatcher = Zizq::Router.new do
17
+ # route("send_email") do |payload|
18
+ # Mailer.deliver(payload["user_id"], payload["template"])
19
+ # end
20
+ #
21
+ # route("expire_tokens") do
22
+ # TokenSweeper.run
23
+ # end
24
+ #
25
+ # route("generate_report") do |payload, job|
26
+ # Reports.generate(payload["id"], attempts: job.attempts)
27
+ # end
28
+ #
29
+ # # `def` inside the block defines singleton methods on the
30
+ # # router. Route blocks captured *inside* the constructor
31
+ # # have lexical `self == router`, so they can call these
32
+ # # helpers; routes added outside (`router.route("…") { … }`)
33
+ # # keep their own lexical `self` and would need to go through
34
+ # # the router explicitly (`router.logger`).
35
+ # def logger
36
+ # Zizq.configuration.logger
37
+ # end
38
+ #
39
+ # # Anything else falls back. A common pattern is delegating
40
+ # # to `Zizq::Job` for the apps that mix the two styles.
41
+ # fallback { |job| Zizq::Job.call(job) }
42
+ # end
43
+ # end
44
+ #
45
+ # Routes can also be registered outside the constructor block:
46
+ #
47
+ # router = Zizq::Router.new
48
+ # router.route("send_email") { |payload| ... }
49
+ #
50
+ # Handlers are called as `handler.call(payload, job)`. Block-arity
51
+ # rules let `{ |payload| }` or `{ }` ignore either argument.
52
+ # Strict-arity lambdas need to declare both.
53
+ class Router
54
+ # Raised when a job arrives with a type that has no registered
55
+ # route and no fallback. Caught by Zizq's normal worker error
56
+ # path, which nacks the job for retry (or dead-letters it once
57
+ # the retry limit is hit).
58
+ class UnknownJobType < Zizq::Error; end
59
+
60
+ # @rbs &block: ?(self) [self: Router] -> void
61
+ def initialize(&block)
62
+ @routes = {} #: Hash[String, ^(untyped, Resources::Job) -> void]
63
+ @fallback = nil #: (^(Resources::Job) -> void)?
64
+ instance_eval(&block) if block
65
+ end
66
+
67
+ # Register `handler` for jobs whose `type` matches.
68
+ #
69
+ # @rbs type: String | Symbol
70
+ # @rbs &handler: (untyped, Resources::Job) -> void
71
+ def route(type, &handler)
72
+ @routes[type.to_s] = handler
73
+ end
74
+
75
+ # Register a fallback handler invoked when no route matches.
76
+ # Receives the full `Resources::Job` (not split into payload /
77
+ # job pair), since the canonical use is delegation to another
78
+ # dispatcher:
79
+ #
80
+ # fallback { |job| Zizq::Job.call(job) }
81
+ #
82
+ # @rbs &handler: (Resources::Job) -> void
83
+ def fallback(&handler)
84
+ @fallback = handler
85
+ end
86
+
87
+ # Dispatch a single job. Looks up the handler by `job.type`,
88
+ # falls back to the registered fallback if any, otherwise
89
+ # raises `UnknownJobType`.
90
+ def call(job) #: (Resources::Job) -> void
91
+ handler = @routes[job.type]
92
+
93
+ return handler.call(job.payload, job) if handler
94
+ return @fallback.call(job) if @fallback
95
+
96
+ raise UnknownJobType,
97
+ "no handler registered for job type #{job.type.inspect}"
98
+ end
99
+ end
100
+ end
data/lib/zizq/version.rb CHANGED
@@ -5,5 +5,5 @@
5
5
  # frozen_string_literal: true
6
6
 
7
7
  module Zizq
8
- VERSION = "0.3.5" #: String
8
+ VERSION = "0.3.6" #: String
9
9
  end
data/lib/zizq.rb CHANGED
@@ -29,6 +29,7 @@ module Zizq
29
29
  autoload :Lifecycle, "zizq/lifecycle"
30
30
  autoload :Query, "zizq/query"
31
31
  autoload :Resources, "zizq/resources"
32
+ autoload :Router, "zizq/router"
32
33
  autoload :Test, "zizq/test"
33
34
  autoload :TlsConfiguration, "zizq/tls_configuration"
34
35
  autoload :Worker, "zizq/worker"
@@ -0,0 +1,81 @@
1
+ # Generated from lib/zizq/router.rb with RBS::Inline
2
+
3
+ module Zizq
4
+ # Dispatch jobs by `type` string, mapping each to a handler block.
5
+ #
6
+ # Designed for cross-language workflows: payloads are plain JSON
7
+ # values (Hashes / Arrays / strings / numbers), `type` is a String
8
+ # the producer agrees on with the consumer, and routes are
9
+ # registered explicitly — no `Zizq::Job` mixin involved.
10
+ #
11
+ # Zizq.configure do |c|
12
+ # c.dispatcher = Zizq::Router.new do
13
+ # route("send_email") do |payload|
14
+ # Mailer.deliver(payload["user_id"], payload["template"])
15
+ # end
16
+ #
17
+ # route("expire_tokens") do
18
+ # TokenSweeper.run
19
+ # end
20
+ #
21
+ # route("generate_report") do |payload, job|
22
+ # Reports.generate(payload["id"], attempts: job.attempts)
23
+ # end
24
+ #
25
+ # # `def` inside the block defines singleton methods on the
26
+ # # router. Route blocks captured *inside* the constructor
27
+ # # have lexical `self == router`, so they can call these
28
+ # # helpers; routes added outside (`router.route("…") { … }`)
29
+ # # keep their own lexical `self` and would need to go through
30
+ # # the router explicitly (`router.logger`).
31
+ # def logger
32
+ # Zizq.configuration.logger
33
+ # end
34
+ #
35
+ # # Anything else falls back. A common pattern is delegating
36
+ # # to `Zizq::Job` for the apps that mix the two styles.
37
+ # fallback { |job| Zizq::Job.call(job) }
38
+ # end
39
+ # end
40
+ #
41
+ # Routes can also be registered outside the constructor block:
42
+ #
43
+ # router = Zizq::Router.new
44
+ # router.route("send_email") { |payload| ... }
45
+ #
46
+ # Handlers are called as `handler.call(payload, job)`. Block-arity
47
+ # rules let `{ |payload| }` or `{ }` ignore either argument.
48
+ # Strict-arity lambdas need to declare both.
49
+ class Router
50
+ # Raised when a job arrives with a type that has no registered
51
+ # route and no fallback. Caught by Zizq's normal worker error
52
+ # path, which nacks the job for retry (or dead-letters it once
53
+ # the retry limit is hit).
54
+ class UnknownJobType < Zizq::Error
55
+ end
56
+
57
+ # @rbs &block: ?(self) [self: Router] -> void
58
+ def initialize: () ?{ (self) [self: Router] -> void } -> untyped
59
+
60
+ # Register `handler` for jobs whose `type` matches.
61
+ #
62
+ # @rbs type: String | Symbol
63
+ # @rbs &handler: (untyped, Resources::Job) -> void
64
+ def route: (String | Symbol type) { (untyped, Resources::Job) -> void } -> untyped
65
+
66
+ # Register a fallback handler invoked when no route matches.
67
+ # Receives the full `Resources::Job` (not split into payload /
68
+ # job pair), since the canonical use is delegation to another
69
+ # dispatcher:
70
+ #
71
+ # fallback { |job| Zizq::Job.call(job) }
72
+ #
73
+ # @rbs &handler: (Resources::Job) -> void
74
+ def fallback: () { (Resources::Job) -> void } -> untyped
75
+
76
+ # Dispatch a single job. Looks up the handler by `job.type`,
77
+ # falls back to the registered fallback if any, otherwise
78
+ # raises `UnknownJobType`.
79
+ def call: (untyped job) -> untyped
80
+ end
81
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zizq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Corbyn <chris@zizq.io>
@@ -100,6 +100,7 @@ files:
100
100
  - lib/zizq/resources/job_template.rb
101
101
  - lib/zizq/resources/page.rb
102
102
  - lib/zizq/resources/resource.rb
103
+ - lib/zizq/router.rb
103
104
  - lib/zizq/test.rb
104
105
  - lib/zizq/test/client.rb
105
106
  - lib/zizq/tls_configuration.rb
@@ -135,6 +136,7 @@ files:
135
136
  - sig/generated/zizq/resources/job_template.rbs
136
137
  - sig/generated/zizq/resources/page.rbs
137
138
  - sig/generated/zizq/resources/resource.rbs
139
+ - sig/generated/zizq/router.rbs
138
140
  - sig/generated/zizq/test.rbs
139
141
  - sig/generated/zizq/test/client.rbs
140
142
  - sig/generated/zizq/tls_configuration.rbs