zizq 0.5.0 → 0.6.0
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 +4 -3
- data/lib/active_job/queue_adapters/zizq_adapter.rb +42 -20
- data/lib/zizq/ack_processor.rb +17 -11
- data/lib/zizq/active_job_config.rb +30 -10
- data/lib/zizq/backoff.rb +5 -1
- data/lib/zizq/bulk_enqueue.rb +7 -1
- data/lib/zizq/client.rb +288 -185
- data/lib/zizq/configuration.rb +15 -14
- data/lib/zizq/crontab.rb +35 -33
- data/lib/zizq/crontab_builder.rb +1 -7
- data/lib/zizq/crontab_entry.rb +36 -35
- data/lib/zizq/crontab_entry_builder.rb +15 -18
- data/lib/zizq/enqueue_request.rb +51 -38
- data/lib/zizq/enqueue_with.rb +1 -3
- data/lib/zizq/error.rb +12 -6
- data/lib/zizq/job.rb +31 -13
- data/lib/zizq/job_config.rb +217 -13
- data/lib/zizq/lifecycle.rb +10 -2
- data/lib/zizq/middleware.rb +7 -6
- data/lib/zizq/query.rb +85 -67
- data/lib/zizq/resources/cron_entry.rb +7 -7
- data/lib/zizq/resources/cron_group.rb +5 -5
- data/lib/zizq/resources/error_enumerator.rb +11 -9
- data/lib/zizq/resources/error_page.rb +2 -1
- data/lib/zizq/resources/error_record.rb +5 -5
- data/lib/zizq/resources/job.rb +41 -24
- data/lib/zizq/resources/job_page.rb +19 -8
- data/lib/zizq/resources/job_template.rb +16 -8
- data/lib/zizq/resources/page.rb +2 -1
- data/lib/zizq/resources/resource.rb +5 -4
- data/lib/zizq/resources.rb +9 -9
- data/lib/zizq/router.rb +3 -2
- data/lib/zizq/test/client.rb +79 -58
- data/lib/zizq/test.rb +8 -8
- data/lib/zizq/tls_configuration.rb +7 -6
- data/lib/zizq/version.rb +1 -1
- data/lib/zizq/worker.rb +68 -50
- data/lib/zizq/worker_configuration.rb +11 -10
- data/lib/zizq.rb +48 -41
- data/sig/generated/zizq/active_job_config.rbs +16 -5
- data/sig/generated/zizq/bulk_enqueue.rbs +1 -0
- data/sig/generated/zizq/client.rbs +2 -1
- data/sig/generated/zizq/crontab_entry_builder.rbs +1 -0
- data/sig/generated/zizq/enqueue_request.rbs +7 -2
- data/sig/generated/zizq/job.rbs +6 -0
- data/sig/generated/zizq/job_config.rbs +98 -0
- data/sig/generated/zizq/resources/job.rbs +2 -0
- data/sig/generated/zizq/resources/job_template.rbs +5 -2
- data/sig/generated/zizq.rbs +1 -0
- data/sig/zizq.rbs +12 -1
- 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: 650d5af8c85dfe12fdf6280a3cf483ba1edd7f7d3d0536965a220c9f556221ef
|
|
4
|
+
data.tar.gz: ec340ce8d30065b6afeb9dc9404651bd769e8a604dec326aca97c332a11bc7ba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7a239bed97e29977c9863f7e56d1ef94b1a1c1cd05bd4b74dde441910bd83f480b4d0453e58b32a3d623ad59bac8b771da5397794e1a05e614e4654cb744606
|
|
7
|
+
data.tar.gz: c60eae8cf1142ecb8e04218d551b5595554ebf5a085076111051c4a658518608715aae729d968d98f33aa7bd3f0f2a181fecbf97a031d6c21bb6a2472d8b291c
|
data/README.md
CHANGED
|
@@ -21,7 +21,8 @@ API.
|
|
|
21
21
|
* Configurable job retention policies
|
|
22
22
|
* Recurring jobs (cron)
|
|
23
23
|
* Job introspection and management APIs, with support for `jq` query filters
|
|
24
|
-
* Unique jobs
|
|
24
|
+
* Unique jobs (deduplicated)
|
|
25
|
+
* Batched jobs (folded/merged)
|
|
25
26
|
* Testing helpers
|
|
26
27
|
|
|
27
28
|
## Installation
|
|
@@ -33,13 +34,13 @@ API.
|
|
|
33
34
|
Add it to your application's `Gemfile`:
|
|
34
35
|
|
|
35
36
|
```ruby
|
|
36
|
-
gem 'zizq', '~> 0.
|
|
37
|
+
gem 'zizq', '~> 0.6.0'
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
Or install it manually:
|
|
40
41
|
|
|
41
42
|
```shell
|
|
42
|
-
$ gem install zizq -v 0.
|
|
43
|
+
$ gem install zizq -v 0.6.0
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
Ruby **3.2.8 or newer** is required. Client and server share version
|
|
@@ -33,7 +33,8 @@ module ActiveJob
|
|
|
33
33
|
class ZizqAdapter
|
|
34
34
|
# Enqueue a job for immediate execution.
|
|
35
35
|
def enqueue(job)
|
|
36
|
-
result =
|
|
36
|
+
result =
|
|
37
|
+
Zizq.enqueue_raw(**build_enqueue_request(job).to_enqueue_params)
|
|
37
38
|
job.provider_job_id = result.id
|
|
38
39
|
job.successfully_enqueued = true
|
|
39
40
|
result
|
|
@@ -42,7 +43,8 @@ module ActiveJob
|
|
|
42
43
|
# Enqueue a job for execution at a specific time.
|
|
43
44
|
def enqueue_at(job, timestamp)
|
|
44
45
|
job.scheduled_at = timestamp
|
|
45
|
-
result =
|
|
46
|
+
result =
|
|
47
|
+
Zizq.enqueue_raw(**build_enqueue_request(job).to_enqueue_params)
|
|
46
48
|
job.provider_job_id = result.id
|
|
47
49
|
job.successfully_enqueued = true
|
|
48
50
|
result
|
|
@@ -53,16 +55,19 @@ module ActiveJob
|
|
|
53
55
|
# Called by `ActiveJob.perform_all_later` (Rails 7.1+).
|
|
54
56
|
# Returns the number of successfully enqueued jobs.
|
|
55
57
|
def enqueue_all(jobs)
|
|
56
|
-
results =
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
results =
|
|
59
|
+
Zizq.enqueue_bulk do |b|
|
|
60
|
+
jobs.each do |job|
|
|
61
|
+
b.enqueue_raw(**build_enqueue_request(job).to_enqueue_params)
|
|
62
|
+
end
|
|
59
63
|
end
|
|
60
|
-
end
|
|
61
64
|
|
|
62
|
-
jobs
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
jobs
|
|
66
|
+
.zip(results)
|
|
67
|
+
.each do |job, result|
|
|
68
|
+
job.provider_job_id = result.id
|
|
69
|
+
job.successfully_enqueued = true
|
|
70
|
+
end
|
|
66
71
|
|
|
67
72
|
jobs.size
|
|
68
73
|
rescue => e
|
|
@@ -85,22 +90,39 @@ module ActiveJob
|
|
|
85
90
|
def build_enqueue_request(job)
|
|
86
91
|
klass = job.class
|
|
87
92
|
|
|
88
|
-
req =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
req =
|
|
94
|
+
Zizq::EnqueueRequest.new(
|
|
95
|
+
queue: job.queue_name,
|
|
96
|
+
type: klass.name,
|
|
97
|
+
payload: job.serialize,
|
|
98
|
+
priority: job.priority,
|
|
99
|
+
ready_at: job.scheduled_at
|
|
100
|
+
)
|
|
95
101
|
|
|
96
102
|
if klass.respond_to?(:zizq_unique) && klass.zizq_unique
|
|
97
103
|
req.unique_key = klass.zizq_unique_key(*job.arguments)
|
|
98
104
|
req.unique_while = klass.zizq_unique_scope
|
|
99
105
|
end
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
if klass.respond_to?(:zizq_batched) && klass.zizq_batched
|
|
108
|
+
expr = klass.zizq_batch_expressions
|
|
109
|
+
if expr
|
|
110
|
+
req.batch = {
|
|
111
|
+
key: klass.zizq_batch_key(*job.arguments),
|
|
112
|
+
when: expr[:when],
|
|
113
|
+
fold: expr[:fold]
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
req.retry_limit = klass.zizq_retry_limit if klass.respond_to?(
|
|
119
|
+
:zizq_retry_limit
|
|
120
|
+
) && klass.zizq_retry_limit
|
|
121
|
+
req.backoff = klass.zizq_backoff if klass.respond_to?(:zizq_backoff) &&
|
|
122
|
+
klass.zizq_backoff
|
|
123
|
+
req.retention = klass.zizq_retention if klass.respond_to?(
|
|
124
|
+
:zizq_retention
|
|
125
|
+
) && klass.zizq_retention
|
|
104
126
|
|
|
105
127
|
req
|
|
106
128
|
end
|
data/lib/zizq/ack_processor.rb
CHANGED
|
@@ -79,13 +79,9 @@ module Zizq
|
|
|
79
79
|
# Partition: acks go bulk, nacks go individually.
|
|
80
80
|
acks, nacks = batch.partition { |i| i.is_a?(Ack) }
|
|
81
81
|
|
|
82
|
-
unless acks.empty?
|
|
83
|
-
barrier.async { process_ack_batch(acks) }
|
|
84
|
-
end
|
|
82
|
+
barrier.async { process_ack_batch(acks) } unless acks.empty?
|
|
85
83
|
|
|
86
|
-
nacks.each
|
|
87
|
-
barrier.async { process_nack(nack) }
|
|
88
|
-
end
|
|
84
|
+
nacks.each { |nack| barrier.async { process_nack(nack) } }
|
|
89
85
|
end
|
|
90
86
|
|
|
91
87
|
barrier.wait
|
|
@@ -101,9 +97,13 @@ module Zizq
|
|
|
101
97
|
begin
|
|
102
98
|
@client.report_success_bulk(ids)
|
|
103
99
|
rescue ClientError => e
|
|
104
|
-
@logger.warn
|
|
100
|
+
@logger.warn do
|
|
101
|
+
"Bulk ack (#{ids.size} jobs) returned #{e.status} (dropping: #{e.message})"
|
|
102
|
+
end
|
|
105
103
|
rescue => e
|
|
106
|
-
@logger.warn
|
|
104
|
+
@logger.warn do
|
|
105
|
+
"Retrying bulk ack (#{ids.size} jobs) in #{backoff.duration}s: #{e.message}"
|
|
106
|
+
end
|
|
107
107
|
backoff.wait
|
|
108
108
|
retry
|
|
109
109
|
end
|
|
@@ -119,11 +119,17 @@ module Zizq
|
|
|
119
119
|
backtrace: nack.backtrace
|
|
120
120
|
)
|
|
121
121
|
rescue NotFoundError
|
|
122
|
-
@logger.debug
|
|
122
|
+
@logger.debug do
|
|
123
|
+
"Nack for #{nack.job_id} returned 404 (already handled)"
|
|
124
|
+
end
|
|
123
125
|
rescue ClientError => e
|
|
124
|
-
@logger.error
|
|
126
|
+
@logger.error do
|
|
127
|
+
"Nack for #{nack.job_id} returned #{e.status} (dropping)"
|
|
128
|
+
end
|
|
125
129
|
rescue => e
|
|
126
|
-
@logger.warn
|
|
130
|
+
@logger.warn do
|
|
131
|
+
"Retrying nack for #{nack.job_id} in #{backoff.duration}s: #{e.message}"
|
|
132
|
+
end
|
|
127
133
|
backoff.wait
|
|
128
134
|
retry
|
|
129
135
|
end
|
|
@@ -65,16 +65,7 @@ module Zizq
|
|
|
65
65
|
# side. This method is not used in the ActiveJob dispatch path.
|
|
66
66
|
def zizq_deserialize(_payload) #: (untyped) -> [Array[untyped], Hash[Symbol, untyped]]
|
|
67
67
|
raise NotImplementedError,
|
|
68
|
-
|
|
69
|
-
end
|
|
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))}"
|
|
68
|
+
"ActiveJob handles deserialization via ActiveJob::Base.execute"
|
|
78
69
|
end
|
|
79
70
|
|
|
80
71
|
# Generate a jq expression that exactly matches payloads with the given
|
|
@@ -139,5 +130,34 @@ module Zizq
|
|
|
139
130
|
|
|
140
131
|
parts.join(" and ")
|
|
141
132
|
end
|
|
133
|
+
|
|
134
|
+
# Static jq expressions for the batched-job configuration on this
|
|
135
|
+
# class. Targets `.arguments[N]` for a positional batch arg or
|
|
136
|
+
# `.arguments[-1].NAME` for a keyword batch arg — the latter
|
|
137
|
+
# assumes the class actually receives kwargs so that the last
|
|
138
|
+
# argument is the ActiveJob kwargs hash. Behaviour is unspecified
|
|
139
|
+
# if the declared `kwarg:` isn't present at enqueue time.
|
|
140
|
+
def zizq_batch_expressions #: () -> Zizq::batch_expressions?
|
|
141
|
+
return nil unless zizq_batched
|
|
142
|
+
|
|
143
|
+
target =
|
|
144
|
+
if (idx = zizq_batch_arg)
|
|
145
|
+
".arguments[#{idx}]"
|
|
146
|
+
else
|
|
147
|
+
".arguments[-1].#{zizq_batch_kwarg}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
build_batch_expressions(target)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
# Hash only the arguments portion of the serialized ActiveJob
|
|
156
|
+
# payload. The full envelope contains volatile fields (job_id,
|
|
157
|
+
# enqueued_at, etc.) that change per instance and would defeat
|
|
158
|
+
# both `zizq_unique_key` and `zizq_batch_key`.
|
|
159
|
+
def hashable_args(*args, **kwargs) #: (*untyped, **untyped) -> untyped
|
|
160
|
+
new(*args, **kwargs).serialize["arguments"]
|
|
161
|
+
end
|
|
142
162
|
end
|
|
143
163
|
end
|
data/lib/zizq/backoff.rb
CHANGED
|
@@ -44,7 +44,11 @@ module Zizq
|
|
|
44
44
|
|
|
45
45
|
# Returns a new Backoff with the same configuration but reset state.
|
|
46
46
|
def fresh #: () -> Backoff
|
|
47
|
-
self.class.new(
|
|
47
|
+
self.class.new(
|
|
48
|
+
min_wait: @min_wait,
|
|
49
|
+
max_wait: @max_wait,
|
|
50
|
+
multiplier: @multiplier
|
|
51
|
+
)
|
|
48
52
|
end
|
|
49
53
|
end
|
|
50
54
|
end
|
data/lib/zizq/bulk_enqueue.rb
CHANGED
|
@@ -28,7 +28,12 @@ module Zizq
|
|
|
28
28
|
# @rbs &block: ?(EnqueueRequest) -> void
|
|
29
29
|
# @rbs return: void
|
|
30
30
|
def enqueue(job_class, *args, **kwargs, &block)
|
|
31
|
-
@requests << Zizq.build_enqueue_request(
|
|
31
|
+
@requests << Zizq.build_enqueue_request(
|
|
32
|
+
job_class,
|
|
33
|
+
*args,
|
|
34
|
+
**kwargs,
|
|
35
|
+
&block
|
|
36
|
+
)
|
|
32
37
|
end
|
|
33
38
|
|
|
34
39
|
# Collect a raw enqueue. Accepts the same arguments as
|
|
@@ -44,6 +49,7 @@ module Zizq
|
|
|
44
49
|
# @rbs retention: Zizq::retention?
|
|
45
50
|
# @rbs unique_key: String?
|
|
46
51
|
# @rbs unique_while: Zizq::unique_scope?
|
|
52
|
+
# @rbs batch: Zizq::batch?
|
|
47
53
|
# @rbs return: void
|
|
48
54
|
def enqueue_raw(queue:, type:, payload:, **opts)
|
|
49
55
|
@requests << EnqueueRequest.new(queue:, type:, payload:, **opts)
|