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 +4 -4
- data/README.md +41 -8
- data/lib/zizq/router.rb +100 -0
- data/lib/zizq/version.rb +1 -1
- data/lib/zizq.rb +1 -0
- data/sig/generated/zizq/router.rbs +81 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a95c96d7b844064db29aea81935d6ec6e3c6953fc47459fcfd6253b6b44aa1e7
|
|
4
|
+
data.tar.gz: 19a8e38ef04716ba02b21bb4ce1f8f2b3e597b1f9845ada71dde5ae7d31fecd3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
|
data/lib/zizq/router.rb
ADDED
|
@@ -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
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.
|
|
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
|