zizq 0.1.0 → 0.2.1
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/lib/zizq/active_job_config.rb +39 -18
- data/lib/zizq/client.rb +31 -0
- data/lib/zizq/query.rb +26 -0
- data/lib/zizq/version.rb +1 -1
- data/lib/zizq.rb +2 -2
- data/sig/generated/zizq/active_job_config.rbs +19 -8
- data/sig/generated/zizq/client.rbs +13 -0
- data/sig/generated/zizq/query.rbs +14 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de36f4f8204a5d5b0c64e77b78249ed34ea6c667ceb6b03dbdca2a291cb0f330
|
|
4
|
+
data.tar.gz: 7cbb62aac1788627bb1047b474e5ca915c5dca059bc6f00be7a2f5adca798a7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95b80cec6e0bb1704bd1244b37c4434b5d5467139e35c61bae39f342825a3e136a413aa55c0a0b7de379024bcdee3486e08cb211062a9d406011093a68de2899
|
|
7
|
+
data.tar.gz: '09952b2563e139e9987473b53524ea993f1c803ea0320082c166132053919f3401cad65c8dc063923837c3b1fe8a505e3e27dcd9ce6a20724313c1d6f82c00e3'
|
|
@@ -9,8 +9,9 @@ require_relative "job_config"
|
|
|
9
9
|
module Zizq
|
|
10
10
|
# Zizq configuration DSL for ActiveJob classes.
|
|
11
11
|
#
|
|
12
|
-
# Extend this module in an ActiveJob subclass to
|
|
13
|
-
# features like unique jobs,
|
|
12
|
+
# Extend this module in an ActiveJob subclass to allow enqueueing jobs via
|
|
13
|
+
# `Zizq.enqueue` and to gain access to Zizq features like unique jobs,
|
|
14
|
+
# backoff, and retention:
|
|
14
15
|
#
|
|
15
16
|
# class SendEmailJob < ApplicationJob
|
|
16
17
|
# extend Zizq::ActiveJobConfig
|
|
@@ -36,17 +37,28 @@ module Zizq
|
|
|
36
37
|
# @rbs!
|
|
37
38
|
# # ActiveJob::Base.new — invisible to steep without this.
|
|
38
39
|
# def new: (*untyped, **untyped) -> untyped
|
|
40
|
+
#
|
|
41
|
+
# # ActiveJob::Base.queue_name — invisible to steep without this.
|
|
42
|
+
# def queue_name: () -> String?
|
|
43
|
+
|
|
44
|
+
# Use ActiveJob's `queue_name` as the default queue, falling back to
|
|
45
|
+
# any explicit `zizq_queue` setting, then "default".
|
|
46
|
+
def zizq_queue(name = nil) #: (?String?) -> String
|
|
47
|
+
if name
|
|
48
|
+
super
|
|
49
|
+
else
|
|
50
|
+
@zizq_queue || queue_name || "default"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
39
53
|
|
|
40
|
-
# Serialize
|
|
54
|
+
# Serialize using ActiveJob's own format.
|
|
41
55
|
#
|
|
42
56
|
# Creates a temporary ActiveJob instance to produce the canonical
|
|
43
|
-
# serialized form
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def zizq_serialize(*args, **kwargs) #: (*untyped, **untyped) -> Array[untyped]
|
|
49
|
-
new(*args, **kwargs).serialize["arguments"]
|
|
57
|
+
# serialized form. Returns the full serialized hash (including
|
|
58
|
+
# `job_class`, `arguments`, `queue_name`, etc.) so that the payload
|
|
59
|
+
# stored in Zizq matches what `ActiveJob::Base.execute` expects.
|
|
60
|
+
def zizq_serialize(*args, **kwargs) #: (*untyped, **untyped) -> Hash[String, untyped]
|
|
61
|
+
new(*args, **kwargs).serialize
|
|
50
62
|
end
|
|
51
63
|
|
|
52
64
|
# Deserialization is handled by ActiveJob::Base.execute on the worker
|
|
@@ -56,6 +68,15 @@ module Zizq
|
|
|
56
68
|
"ActiveJob handles deserialization via ActiveJob::Base.execute"
|
|
57
69
|
end
|
|
58
70
|
|
|
71
|
+
# Override unique key generation to hash only the arguments portion
|
|
72
|
+
# of the serialized payload. The full payload contains volatile fields
|
|
73
|
+
# (job_id, enqueued_at, etc.) that change per instance.
|
|
74
|
+
def zizq_unique_key(*args, **kwargs) #: (*untyped, **untyped) -> String
|
|
75
|
+
arguments = new(*args, **kwargs).serialize["arguments"]
|
|
76
|
+
payload = normalize_payload(arguments)
|
|
77
|
+
"#{name}:#{Digest::SHA256.hexdigest(JSON.generate(payload))}"
|
|
78
|
+
end
|
|
79
|
+
|
|
59
80
|
# Generate a jq expression that exactly matches payloads with the given
|
|
60
81
|
# arguments.
|
|
61
82
|
#
|
|
@@ -65,8 +86,8 @@ module Zizq
|
|
|
65
86
|
#
|
|
66
87
|
# .arguments == ["a","b",{"example":true,"_aj_ruby2_keywords":["example"]}]
|
|
67
88
|
def zizq_payload_filter(*args, **kwargs) #: (*untyped, **untyped) -> String
|
|
68
|
-
|
|
69
|
-
".arguments == #{JSON.generate(
|
|
89
|
+
arguments = zizq_serialize(*args, **kwargs)["arguments"]
|
|
90
|
+
".arguments == #{JSON.generate(arguments)}"
|
|
70
91
|
end
|
|
71
92
|
|
|
72
93
|
# Generate a jq expression that matches jobs whose positional args
|
|
@@ -85,27 +106,27 @@ module Zizq
|
|
|
85
106
|
# (.arguments[-1] | has("_aj_ruby2_keywords")) and
|
|
86
107
|
# (.arguments[-1] | contains({"example":true}))
|
|
87
108
|
def zizq_payload_subset_filter(*args, **kwargs) #: (*untyped, **untyped) -> String
|
|
88
|
-
|
|
109
|
+
arguments = zizq_serialize(*args, **kwargs)["arguments"]
|
|
89
110
|
|
|
90
111
|
# ActiveJob flattens arguments into a single array, but marks kwargs with
|
|
91
112
|
# "_aj_ruby2_keywords" => ["key1", "key2", ...] in the last element of
|
|
92
113
|
# the array where kwargs are present. We need to detect this to generate
|
|
93
114
|
# a suitable expression.
|
|
94
115
|
serialized_args, serialized_kwargs =
|
|
95
|
-
if
|
|
116
|
+
if arguments.size > 0
|
|
96
117
|
# See what the last argument looks like. It might be kwargs.
|
|
97
|
-
maybe_kwargs =
|
|
118
|
+
maybe_kwargs = arguments.pop
|
|
98
119
|
|
|
99
120
|
# If it's got "_aj_ruby2_keywords" then it is kwargs.
|
|
100
121
|
if maybe_kwargs.is_a?(Hash) && maybe_kwargs["_aj_ruby2_keywords"]
|
|
101
122
|
# We only want the actual kwargs, not the marker.
|
|
102
|
-
[
|
|
123
|
+
[arguments, maybe_kwargs.except("_aj_ruby2_keywords")]
|
|
103
124
|
else
|
|
104
125
|
# It wasn't kwargs, so put it back.
|
|
105
|
-
[
|
|
126
|
+
[arguments.push(maybe_kwargs), nil]
|
|
106
127
|
end
|
|
107
128
|
else
|
|
108
|
-
[
|
|
129
|
+
[arguments, nil]
|
|
109
130
|
end
|
|
110
131
|
|
|
111
132
|
parts = [] #: Array[String]
|
data/lib/zizq/client.rb
CHANGED
|
@@ -249,6 +249,37 @@ module Zizq
|
|
|
249
249
|
Resources::JobPage.new(self, data)
|
|
250
250
|
end
|
|
251
251
|
|
|
252
|
+
# Count jobs matching the given filters.
|
|
253
|
+
#
|
|
254
|
+
# Accepts the same filter arguments as `list_jobs` (minus pagination).
|
|
255
|
+
# Returns the count as an integer.
|
|
256
|
+
#
|
|
257
|
+
# @rbs id: (String | Array[String])?
|
|
258
|
+
# @rbs status: (String | Array[String])?
|
|
259
|
+
# @rbs queue: (String | Array[String])?
|
|
260
|
+
# @rbs type: (String | Array[String])?
|
|
261
|
+
# @rbs filter: String?
|
|
262
|
+
# @rbs return: Integer
|
|
263
|
+
def count_jobs(id: nil,
|
|
264
|
+
status: nil,
|
|
265
|
+
queue: nil,
|
|
266
|
+
type: nil,
|
|
267
|
+
filter: nil)
|
|
268
|
+
options = { id:, status:, queue:, type:, filter: }.compact #: Hash[Symbol, untyped]
|
|
269
|
+
|
|
270
|
+
multi_keys = %i[id status queue type]
|
|
271
|
+
params = build_where_params(options, multi_keys:)
|
|
272
|
+
|
|
273
|
+
# An empty filter ([] or "") matches nothing — short-circuit.
|
|
274
|
+
multi_keys.each do |key|
|
|
275
|
+
return 0 if params[key] == ""
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
response = get("/jobs/count", params:)
|
|
279
|
+
data = handle_response!(response, expected: 200)
|
|
280
|
+
data.fetch("count")
|
|
281
|
+
end
|
|
282
|
+
|
|
252
283
|
# Delete a single job by ID.
|
|
253
284
|
#
|
|
254
285
|
# @rbs id: String
|
data/lib/zizq/query.rb
CHANGED
|
@@ -283,6 +283,32 @@ module Zizq
|
|
|
283
283
|
limit(2).to_a.size == 1
|
|
284
284
|
end
|
|
285
285
|
|
|
286
|
+
# Count matching jobs via the server-side count endpoint.
|
|
287
|
+
#
|
|
288
|
+
# Without a block or argument, uses `GET /jobs/count` for an efficient
|
|
289
|
+
# server-side count. When a limit is set, caps the result locally with
|
|
290
|
+
# `[total, limit].min`.
|
|
291
|
+
#
|
|
292
|
+
# With a block or argument, falls back to Enumerable (iterates and counts
|
|
293
|
+
# matching jobs).
|
|
294
|
+
#
|
|
295
|
+
# @rbs *args: untyped
|
|
296
|
+
# @rbs &block: ?(Resources::Job) -> bool
|
|
297
|
+
# @rbs return: Integer
|
|
298
|
+
def count(*args, &block)
|
|
299
|
+
return super if block || !args.empty?
|
|
300
|
+
|
|
301
|
+
total = Zizq.client.count_jobs(
|
|
302
|
+
id: @id,
|
|
303
|
+
queue: @queue,
|
|
304
|
+
type: @type,
|
|
305
|
+
status: @status,
|
|
306
|
+
filter: @jq_filter,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
@limit ? [total, @limit].min : total
|
|
310
|
+
end
|
|
311
|
+
|
|
286
312
|
# Iterate over matching jobs in reverse order.
|
|
287
313
|
#
|
|
288
314
|
# Optimised: pushes the reverse ordering to the server instead of
|
data/lib/zizq/version.rb
CHANGED
data/lib/zizq.rb
CHANGED
|
@@ -253,8 +253,8 @@ module Zizq
|
|
|
253
253
|
# @rbs &block: ?(EnqueueRequest) -> void
|
|
254
254
|
# @rbs return: EnqueueRequest
|
|
255
255
|
def build_enqueue_request(job_class, *args, **kwargs, &block)
|
|
256
|
-
unless job_class.is_a?(Class) && job_class
|
|
257
|
-
raise ArgumentError, "#{job_class.inspect} must include Zizq::Job"
|
|
256
|
+
unless job_class.is_a?(Class) && job_class.is_a?(Zizq::JobConfig)
|
|
257
|
+
raise ArgumentError, "#{job_class.inspect} must include Zizq::Job or extend Zizq::ActiveJobConfig"
|
|
258
258
|
end
|
|
259
259
|
|
|
260
260
|
zizq_job_class = job_class #: Zizq::job_class
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
module Zizq
|
|
4
4
|
# Zizq configuration DSL for ActiveJob classes.
|
|
5
5
|
#
|
|
6
|
-
# Extend this module in an ActiveJob subclass to
|
|
7
|
-
# features like unique jobs,
|
|
6
|
+
# Extend this module in an ActiveJob subclass to allow enqueueing jobs via
|
|
7
|
+
# `Zizq.enqueue` and to gain access to Zizq features like unique jobs,
|
|
8
|
+
# backoff, and retention:
|
|
8
9
|
#
|
|
9
10
|
# class SendEmailJob < ApplicationJob
|
|
10
11
|
# extend Zizq::ActiveJobConfig
|
|
@@ -30,20 +31,30 @@ module Zizq
|
|
|
30
31
|
# ActiveJob::Base.new — invisible to steep without this.
|
|
31
32
|
def new: (*untyped, **untyped) -> untyped
|
|
32
33
|
|
|
33
|
-
#
|
|
34
|
+
# ActiveJob::Base.queue_name — invisible to steep without this.
|
|
35
|
+
def queue_name: () -> String?
|
|
36
|
+
|
|
37
|
+
# Use ActiveJob's `queue_name` as the default queue, falling back to
|
|
38
|
+
# any explicit `zizq_queue` setting, then "default".
|
|
39
|
+
def zizq_queue: (?untyped name) -> untyped
|
|
40
|
+
|
|
41
|
+
# Serialize using ActiveJob's own format.
|
|
34
42
|
#
|
|
35
43
|
# Creates a temporary ActiveJob instance to produce the canonical
|
|
36
|
-
# serialized form
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# This is needed so that unique job keys can be correctly generated.
|
|
44
|
+
# serialized form. Returns the full serialized hash (including
|
|
45
|
+
# `job_class`, `arguments`, `queue_name`, etc.) so that the payload
|
|
46
|
+
# stored in Zizq matches what `ActiveJob::Base.execute` expects.
|
|
41
47
|
def zizq_serialize: (*untyped args, **untyped kwargs) -> untyped
|
|
42
48
|
|
|
43
49
|
# Deserialization is handled by ActiveJob::Base.execute on the worker
|
|
44
50
|
# side. This method is not used in the ActiveJob dispatch path.
|
|
45
51
|
def zizq_deserialize: (untyped _payload) -> untyped
|
|
46
52
|
|
|
53
|
+
# Override unique key generation to hash only the arguments portion
|
|
54
|
+
# of the serialized payload. The full payload contains volatile fields
|
|
55
|
+
# (job_id, enqueued_at, etc.) that change per instance.
|
|
56
|
+
def zizq_unique_key: (*untyped args, **untyped kwargs) -> untyped
|
|
57
|
+
|
|
47
58
|
# Generate a jq expression that exactly matches payloads with the given
|
|
48
59
|
# arguments.
|
|
49
60
|
#
|
|
@@ -108,6 +108,19 @@ module Zizq
|
|
|
108
108
|
# @rbs return: Resources::JobPage
|
|
109
109
|
def list_jobs: (?id: (String | Array[String])?, ?status: (String | Array[String])?, ?queue: (String | Array[String])?, ?type: (String | Array[String])?, ?filter: String?, ?from: String?, ?order: Zizq::sort_direction?, ?limit: Integer?) -> Resources::JobPage
|
|
110
110
|
|
|
111
|
+
# Count jobs matching the given filters.
|
|
112
|
+
#
|
|
113
|
+
# Accepts the same filter arguments as `list_jobs` (minus pagination).
|
|
114
|
+
# Returns the count as an integer.
|
|
115
|
+
#
|
|
116
|
+
# @rbs id: (String | Array[String])?
|
|
117
|
+
# @rbs status: (String | Array[String])?
|
|
118
|
+
# @rbs queue: (String | Array[String])?
|
|
119
|
+
# @rbs type: (String | Array[String])?
|
|
120
|
+
# @rbs filter: String?
|
|
121
|
+
# @rbs return: Integer
|
|
122
|
+
def count_jobs: (?id: (String | Array[String])?, ?status: (String | Array[String])?, ?queue: (String | Array[String])?, ?type: (String | Array[String])?, ?filter: String?) -> Integer
|
|
123
|
+
|
|
111
124
|
# Delete a single job by ID.
|
|
112
125
|
#
|
|
113
126
|
# @rbs id: String
|
|
@@ -208,6 +208,20 @@ module Zizq
|
|
|
208
208
|
# @rbs return: bool
|
|
209
209
|
def one?: () ?{ (Resources::Job) -> bool } -> bool
|
|
210
210
|
|
|
211
|
+
# Count matching jobs via the server-side count endpoint.
|
|
212
|
+
#
|
|
213
|
+
# Without a block or argument, uses `GET /jobs/count` for an efficient
|
|
214
|
+
# server-side count. When a limit is set, caps the result locally with
|
|
215
|
+
# `[total, limit].min`.
|
|
216
|
+
#
|
|
217
|
+
# With a block or argument, falls back to Enumerable (iterates and counts
|
|
218
|
+
# matching jobs).
|
|
219
|
+
#
|
|
220
|
+
# @rbs *args: untyped
|
|
221
|
+
# @rbs &block: ?(Resources::Job) -> bool
|
|
222
|
+
# @rbs return: Integer
|
|
223
|
+
def count: (*untyped args) ?{ (Resources::Job) -> bool } -> Integer
|
|
224
|
+
|
|
211
225
|
# Iterate over matching jobs in reverse order.
|
|
212
226
|
#
|
|
213
227
|
# Optimised: pushes the reverse ordering to the server instead of
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zizq
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Corbyn <chris@zizq.io>
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: async-http
|