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
data/lib/zizq/client.rb
CHANGED
|
@@ -62,24 +62,23 @@ module Zizq
|
|
|
62
62
|
# @rbs read_timeout: Numeric
|
|
63
63
|
# @rbs stream_idle_timeout: Numeric
|
|
64
64
|
# @rbs return: void
|
|
65
|
-
def initialize(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
def initialize(
|
|
66
|
+
url:,
|
|
67
|
+
format: :msgpack,
|
|
68
|
+
ssl_context: nil,
|
|
69
|
+
read_timeout: 30,
|
|
70
|
+
stream_idle_timeout: 30
|
|
71
|
+
)
|
|
70
72
|
@url = url.chomp("/")
|
|
71
73
|
@format = format
|
|
72
74
|
|
|
73
75
|
endpoint_options = {
|
|
74
76
|
protocol: Async::HTTP::Protocol::HTTP2,
|
|
75
|
-
timeout: read_timeout
|
|
77
|
+
timeout: read_timeout
|
|
76
78
|
} #: Hash[Symbol, untyped]
|
|
77
79
|
endpoint_options[:ssl_context] = ssl_context if ssl_context
|
|
78
80
|
|
|
79
|
-
@endpoint = Async::HTTP::Endpoint.parse(
|
|
80
|
-
@url,
|
|
81
|
-
**endpoint_options,
|
|
82
|
-
)
|
|
81
|
+
@endpoint = Async::HTTP::Endpoint.parse(@url, **endpoint_options)
|
|
83
82
|
|
|
84
83
|
# Streaming take uses a dedicated HTTP/1.1 endpoint. The take
|
|
85
84
|
# connection is long-lived and carries only one request, so HTTP/2's
|
|
@@ -93,14 +92,13 @@ module Zizq
|
|
|
93
92
|
# timeout so server heartbeats (~3s) keep it alive while only
|
|
94
93
|
# genuinely dead connections (no data for the full window)
|
|
95
94
|
# trigger a reconnect.
|
|
96
|
-
stream_endpoint_options =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
**stream_endpoint_options
|
|
103
|
-
)
|
|
95
|
+
stream_endpoint_options =
|
|
96
|
+
endpoint_options.merge(
|
|
97
|
+
protocol: Async::HTTP::Protocol::HTTP11,
|
|
98
|
+
timeout: stream_idle_timeout
|
|
99
|
+
)
|
|
100
|
+
@stream_endpoint =
|
|
101
|
+
Async::HTTP::Endpoint.parse(@url, **stream_endpoint_options)
|
|
104
102
|
|
|
105
103
|
@mutex = Mutex.new
|
|
106
104
|
|
|
@@ -166,17 +164,21 @@ module Zizq
|
|
|
166
164
|
# @rbs retention: Zizq::retention?
|
|
167
165
|
# @rbs unique_key: String?
|
|
168
166
|
# @rbs unique_while: Zizq::unique_scope?
|
|
167
|
+
# @rbs batch: Zizq::batch?
|
|
169
168
|
# @rbs return: Resources::Job
|
|
170
|
-
def enqueue(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
169
|
+
def enqueue(
|
|
170
|
+
queue:,
|
|
171
|
+
type:,
|
|
172
|
+
payload:,
|
|
173
|
+
priority: nil,
|
|
174
|
+
ready_at: nil,
|
|
175
|
+
retry_limit: nil,
|
|
176
|
+
backoff: nil,
|
|
177
|
+
retention: nil,
|
|
178
|
+
unique_key: nil,
|
|
179
|
+
unique_while: nil,
|
|
180
|
+
batch: nil
|
|
181
|
+
)
|
|
180
182
|
body = { queue:, type:, payload: } #: Hash[Symbol, untyped]
|
|
181
183
|
body[:priority] = priority if priority
|
|
182
184
|
# ready_at is fractional seconds in Ruby; the server expects ms.
|
|
@@ -186,6 +188,7 @@ module Zizq
|
|
|
186
188
|
body[:retention] = retention if retention
|
|
187
189
|
body[:unique_key] = unique_key if unique_key
|
|
188
190
|
body[:unique_while] = unique_while.to_s if unique_while
|
|
191
|
+
body[:batch] = batch if batch
|
|
189
192
|
|
|
190
193
|
response = post("/jobs", body)
|
|
191
194
|
data = handle_response!(response, expected: [200, 201])
|
|
@@ -204,18 +207,26 @@ module Zizq
|
|
|
204
207
|
# @rbs return: Array[Resources::Job]
|
|
205
208
|
def enqueue_bulk(jobs:)
|
|
206
209
|
body = {
|
|
207
|
-
jobs:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
210
|
+
jobs:
|
|
211
|
+
jobs.map do |job|
|
|
212
|
+
wire = {
|
|
213
|
+
type: job[:type],
|
|
214
|
+
queue: job[:queue],
|
|
215
|
+
payload: job[:payload]
|
|
216
|
+
} #: Hash[Symbol, untyped]
|
|
217
|
+
wire[:priority] = job[:priority] if job[:priority]
|
|
218
|
+
# ready_at is fractional seconds in Ruby; the server expects ms.
|
|
219
|
+
wire[:ready_at] = (job[:ready_at].to_f * 1000).to_i if job[
|
|
220
|
+
:ready_at
|
|
221
|
+
]
|
|
222
|
+
wire[:retry_limit] = job[:retry_limit] if job[:retry_limit]
|
|
223
|
+
wire[:backoff] = job[:backoff] if job[:backoff]
|
|
224
|
+
wire[:retention] = job[:retention] if job[:retention]
|
|
225
|
+
wire[:unique_key] = job[:unique_key] if job[:unique_key]
|
|
226
|
+
wire[:unique_while] = job[:unique_while].to_s if job[:unique_while]
|
|
227
|
+
wire[:batch] = job[:batch] if job[:batch]
|
|
228
|
+
wire
|
|
229
|
+
end
|
|
219
230
|
}
|
|
220
231
|
|
|
221
232
|
response = post("/jobs/bulk", body)
|
|
@@ -253,17 +264,19 @@ module Zizq
|
|
|
253
264
|
# @rbs order: Zizq::sort_direction?
|
|
254
265
|
# @rbs limit: Integer?
|
|
255
266
|
# @rbs return: Resources::JobPage
|
|
256
|
-
def list_jobs(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
+
def list_jobs(
|
|
268
|
+
id: nil,
|
|
269
|
+
status: nil,
|
|
270
|
+
queue: nil,
|
|
271
|
+
type: nil,
|
|
272
|
+
filter: nil,
|
|
273
|
+
priority: nil,
|
|
274
|
+
ready_at: nil,
|
|
275
|
+
attempts: nil,
|
|
276
|
+
from: nil,
|
|
277
|
+
order: nil,
|
|
278
|
+
limit: nil
|
|
279
|
+
)
|
|
267
280
|
options = {
|
|
268
281
|
id:,
|
|
269
282
|
status:,
|
|
@@ -275,7 +288,7 @@ module Zizq
|
|
|
275
288
|
attempts: encode_range(attempts),
|
|
276
289
|
from:,
|
|
277
290
|
order:,
|
|
278
|
-
limit
|
|
291
|
+
limit:
|
|
279
292
|
}.compact #: Hash[Symbol, untyped]
|
|
280
293
|
|
|
281
294
|
multi_keys = %i[id status queue type]
|
|
@@ -283,7 +296,9 @@ module Zizq
|
|
|
283
296
|
|
|
284
297
|
# An empty filter ([] or "") matches nothing — short-circuit.
|
|
285
298
|
multi_keys.each do |key|
|
|
286
|
-
|
|
299
|
+
if params[key] == ""
|
|
300
|
+
return Resources::JobPage.new(self, { "jobs" => [], "pages" => {} })
|
|
301
|
+
end
|
|
287
302
|
end
|
|
288
303
|
|
|
289
304
|
response = get("/jobs", params:)
|
|
@@ -305,14 +320,16 @@ module Zizq
|
|
|
305
320
|
# @rbs ready_at: (Zizq::to_f | Range[Zizq::to_f?])?
|
|
306
321
|
# @rbs attempts: (Integer | Range[Integer?])?
|
|
307
322
|
# @rbs return: Integer
|
|
308
|
-
def count_jobs(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
323
|
+
def count_jobs(
|
|
324
|
+
id: nil,
|
|
325
|
+
status: nil,
|
|
326
|
+
queue: nil,
|
|
327
|
+
type: nil,
|
|
328
|
+
filter: nil,
|
|
329
|
+
priority: nil,
|
|
330
|
+
ready_at: nil,
|
|
331
|
+
attempts: nil
|
|
332
|
+
)
|
|
316
333
|
options = {
|
|
317
334
|
id:,
|
|
318
335
|
status:,
|
|
@@ -321,16 +338,14 @@ module Zizq
|
|
|
321
338
|
filter:,
|
|
322
339
|
priority: encode_range(priority),
|
|
323
340
|
ready_at: encode_range(ready_at) { |v| (v.to_f * 1000).to_i },
|
|
324
|
-
attempts: encode_range(attempts)
|
|
341
|
+
attempts: encode_range(attempts)
|
|
325
342
|
}.compact #: Hash[Symbol, untyped]
|
|
326
343
|
|
|
327
344
|
multi_keys = %i[id status queue type]
|
|
328
345
|
params = build_where_params(options, multi_keys:)
|
|
329
346
|
|
|
330
347
|
# An empty filter ([] or "") matches nothing — short-circuit.
|
|
331
|
-
multi_keys.each
|
|
332
|
-
return 0 if params[key] == ""
|
|
333
|
-
end
|
|
348
|
+
multi_keys.each { |key| return 0 if params[key] == "" }
|
|
334
349
|
|
|
335
350
|
response = get("/jobs/count", params:)
|
|
336
351
|
data = handle_response!(response, expected: 200)
|
|
@@ -363,9 +378,7 @@ module Zizq
|
|
|
363
378
|
params = build_where_params(filter_params, multi_keys:)
|
|
364
379
|
|
|
365
380
|
# An empty multi-value filter matches nothing — short-circuit.
|
|
366
|
-
multi_keys.each
|
|
367
|
-
return 0 if params[key] == ""
|
|
368
|
-
end
|
|
381
|
+
multi_keys.each { |key| return 0 if params[key] == "" }
|
|
369
382
|
|
|
370
383
|
response = delete("/jobs", params:)
|
|
371
384
|
data = handle_response!(response, expected: 200)
|
|
@@ -408,21 +421,24 @@ module Zizq
|
|
|
408
421
|
# @rbs backoff: (Zizq::backoff | singleton(Zizq::RESET) | singleton(Zizq::UNCHANGED))?
|
|
409
422
|
# @rbs retention: (Zizq::retention | singleton(Zizq::RESET) | singleton(Zizq::UNCHANGED))?
|
|
410
423
|
# @rbs return: Resources::Job
|
|
411
|
-
def update_job(
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
def update_job(
|
|
425
|
+
id,
|
|
426
|
+
queue: UNCHANGED,
|
|
427
|
+
priority: UNCHANGED,
|
|
428
|
+
ready_at: UNCHANGED,
|
|
429
|
+
retry_limit: UNCHANGED,
|
|
430
|
+
backoff: UNCHANGED,
|
|
431
|
+
retention: UNCHANGED
|
|
432
|
+
)
|
|
433
|
+
body =
|
|
434
|
+
build_set_body(
|
|
435
|
+
queue:,
|
|
436
|
+
priority:,
|
|
437
|
+
ready_at:,
|
|
438
|
+
retry_limit:,
|
|
439
|
+
backoff:,
|
|
440
|
+
retention:
|
|
441
|
+
)
|
|
426
442
|
response = patch("/jobs/#{enc(id)}", body)
|
|
427
443
|
data = handle_response!(response, expected: 200)
|
|
428
444
|
Resources::Job.new(self, data)
|
|
@@ -448,9 +464,7 @@ module Zizq
|
|
|
448
464
|
params = build_where_params(filter_params, multi_keys:)
|
|
449
465
|
|
|
450
466
|
# An empty multi-value filter matches nothing — short-circuit.
|
|
451
|
-
multi_keys.each
|
|
452
|
-
return 0 if params[key] == ""
|
|
453
|
-
end
|
|
467
|
+
multi_keys.each { |key| return 0 if params[key] == "" }
|
|
454
468
|
|
|
455
469
|
body = validate_and_build_set(**apply)
|
|
456
470
|
response = patch("/jobs", body, params:)
|
|
@@ -602,7 +616,14 @@ module Zizq
|
|
|
602
616
|
# @rbs timezone: String?
|
|
603
617
|
# @rbs paused: bool?
|
|
604
618
|
# @rbs return: Resources::CronEntry
|
|
605
|
-
def add_cron_group_entry(
|
|
619
|
+
def add_cron_group_entry(
|
|
620
|
+
group,
|
|
621
|
+
name:,
|
|
622
|
+
expression:,
|
|
623
|
+
job:,
|
|
624
|
+
timezone: nil,
|
|
625
|
+
paused: nil
|
|
626
|
+
)
|
|
606
627
|
body = build_cron_entry(name:, expression:, job:, timezone:, paused:)
|
|
607
628
|
response = post("/crons/#{enc(group)}/entries", body)
|
|
608
629
|
data = handle_response!(response, expected: 201)
|
|
@@ -620,8 +641,16 @@ module Zizq
|
|
|
620
641
|
# @rbs timezone: String?
|
|
621
642
|
# @rbs paused: bool?
|
|
622
643
|
# @rbs return: Resources::CronEntry
|
|
623
|
-
def replace_cron_group_entry(
|
|
624
|
-
|
|
644
|
+
def replace_cron_group_entry(
|
|
645
|
+
group,
|
|
646
|
+
entry,
|
|
647
|
+
expression:,
|
|
648
|
+
job:,
|
|
649
|
+
timezone: nil,
|
|
650
|
+
paused: nil
|
|
651
|
+
)
|
|
652
|
+
body =
|
|
653
|
+
build_cron_entry(name: entry, expression:, job:, timezone:, paused:)
|
|
625
654
|
response = put("/crons/#{enc(group)}/entries/#{enc(entry)}", body)
|
|
626
655
|
data = handle_response!(response, expected: 200)
|
|
627
656
|
Resources::CronEntry.new(self, data)
|
|
@@ -634,7 +663,8 @@ module Zizq
|
|
|
634
663
|
# @rbs paused: bool
|
|
635
664
|
# @rbs return: Resources::CronEntry
|
|
636
665
|
def update_cron_group_entry(group, entry, paused:)
|
|
637
|
-
response =
|
|
666
|
+
response =
|
|
667
|
+
patch("/crons/#{enc(group)}/entries/#{enc(entry)}", { paused: })
|
|
638
668
|
data = handle_response!(response, expected: 200)
|
|
639
669
|
Resources::CronEntry.new(self, data)
|
|
640
670
|
end
|
|
@@ -723,7 +753,14 @@ module Zizq
|
|
|
723
753
|
# @rbs retry_at: Float?
|
|
724
754
|
# @rbs kill: bool
|
|
725
755
|
# @rbs return: Resources::Job
|
|
726
|
-
def report_failure(
|
|
756
|
+
def report_failure(
|
|
757
|
+
id,
|
|
758
|
+
message:,
|
|
759
|
+
error_type: nil,
|
|
760
|
+
backtrace: nil,
|
|
761
|
+
retry_at: nil,
|
|
762
|
+
kill: false
|
|
763
|
+
)
|
|
727
764
|
body = { message: } #: Hash[Symbol, untyped]
|
|
728
765
|
body[:error_type] = error_type if error_type
|
|
729
766
|
body[:backtrace] = backtrace if backtrace
|
|
@@ -772,7 +809,14 @@ module Zizq
|
|
|
772
809
|
# @rbs worker_id: String?
|
|
773
810
|
# @rbs &block: (Resources::Job) -> void
|
|
774
811
|
# @rbs return: void
|
|
775
|
-
def take_jobs(
|
|
812
|
+
def take_jobs(
|
|
813
|
+
prefetch: 1,
|
|
814
|
+
queues: [],
|
|
815
|
+
worker_id: nil,
|
|
816
|
+
on_connect: nil,
|
|
817
|
+
on_response: nil,
|
|
818
|
+
&block
|
|
819
|
+
)
|
|
776
820
|
raise ArgumentError, "take_jobs requires a block" unless block
|
|
777
821
|
|
|
778
822
|
params = { prefetch: } #: Hash[Symbol, untyped]
|
|
@@ -786,7 +830,10 @@ module Zizq
|
|
|
786
830
|
response = stream_http.get(path, headers)
|
|
787
831
|
|
|
788
832
|
begin
|
|
789
|
-
|
|
833
|
+
unless response.status == 200
|
|
834
|
+
raise StreamError,
|
|
835
|
+
"take jobs stream returned HTTP #{response.status}"
|
|
836
|
+
end
|
|
790
837
|
on_connect&.call
|
|
791
838
|
on_response&.call(response)
|
|
792
839
|
|
|
@@ -800,11 +847,17 @@ module Zizq
|
|
|
800
847
|
body = response.body || []
|
|
801
848
|
|
|
802
849
|
case @format
|
|
803
|
-
when :json
|
|
804
|
-
|
|
850
|
+
when :json
|
|
851
|
+
self.class.parse_ndjson(body, &wrapper)
|
|
852
|
+
when :msgpack
|
|
853
|
+
self.class.parse_msgpack_stream(body, &wrapper)
|
|
805
854
|
end
|
|
806
855
|
ensure
|
|
807
|
-
|
|
856
|
+
begin
|
|
857
|
+
response.close
|
|
858
|
+
rescue StandardError
|
|
859
|
+
nil
|
|
860
|
+
end
|
|
808
861
|
end
|
|
809
862
|
end
|
|
810
863
|
rescue SocketError,
|
|
@@ -887,7 +940,10 @@ module Zizq
|
|
|
887
940
|
# so that resource objects like Page can follow links without resorting
|
|
888
941
|
# to `.send`.
|
|
889
942
|
def get_path(path) #: (String) -> Hash[String, untyped]
|
|
890
|
-
response =
|
|
943
|
+
response =
|
|
944
|
+
request do |http|
|
|
945
|
+
consume_response(http.get(path, { "accept" => @content_type }))
|
|
946
|
+
end
|
|
891
947
|
handle_response!(response, expected: 200)
|
|
892
948
|
end
|
|
893
949
|
|
|
@@ -900,9 +956,7 @@ module Zizq
|
|
|
900
956
|
|
|
901
957
|
# Build a relative path with optional query parameters.
|
|
902
958
|
def build_path(path, params: {}) #: (String, ?params: Hash[Symbol, untyped]) -> String
|
|
903
|
-
unless params.empty?
|
|
904
|
-
path = "#{path}?#{URI.encode_www_form(params)}"
|
|
905
|
-
end
|
|
959
|
+
path = "#{path}?#{URI.encode_www_form(params)}" unless params.empty?
|
|
906
960
|
path
|
|
907
961
|
end
|
|
908
962
|
|
|
@@ -914,13 +968,19 @@ module Zizq
|
|
|
914
968
|
# @rbs timezone: String?
|
|
915
969
|
# @rbs paused: bool?
|
|
916
970
|
# @rbs return: Hash[Symbol, untyped]
|
|
917
|
-
def build_cron_entry(
|
|
971
|
+
def build_cron_entry(
|
|
972
|
+
name: nil,
|
|
973
|
+
expression: nil,
|
|
974
|
+
job: nil,
|
|
975
|
+
timezone: nil,
|
|
976
|
+
paused: nil
|
|
977
|
+
)
|
|
918
978
|
{
|
|
919
979
|
name:,
|
|
920
980
|
expression:,
|
|
921
981
|
timezone:,
|
|
922
982
|
paused:,
|
|
923
|
-
job: build_cron_job(**job)
|
|
983
|
+
job: build_cron_job(**job)
|
|
924
984
|
}.compact
|
|
925
985
|
end
|
|
926
986
|
|
|
@@ -938,15 +998,17 @@ module Zizq
|
|
|
938
998
|
# @rbs unique_key: String?
|
|
939
999
|
# @rbs unique_while: Zizq::unique_scope?
|
|
940
1000
|
# @rbs return: Hash[Symbol, untyped]
|
|
941
|
-
def build_cron_job(
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1001
|
+
def build_cron_job(
|
|
1002
|
+
type: nil,
|
|
1003
|
+
queue: nil,
|
|
1004
|
+
payload: nil,
|
|
1005
|
+
priority: nil,
|
|
1006
|
+
retry_limit: nil,
|
|
1007
|
+
backoff: nil,
|
|
1008
|
+
retention: nil,
|
|
1009
|
+
unique_key: nil,
|
|
1010
|
+
unique_while: nil
|
|
1011
|
+
)
|
|
950
1012
|
job = { type:, queue:, payload: } #: Hash[Symbol, untyped]
|
|
951
1013
|
job[:priority] = priority if priority
|
|
952
1014
|
job[:retry_limit] = retry_limit if retry_limit
|
|
@@ -970,14 +1032,16 @@ module Zizq
|
|
|
970
1032
|
# @rbs ready_at: (Zizq::to_f | Range[Zizq::to_f?])?
|
|
971
1033
|
# @rbs attempts: (Integer | Range[Integer?])?
|
|
972
1034
|
# @rbs return: Hash[Symbol, untyped]
|
|
973
|
-
def validate_where(
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1035
|
+
def validate_where(
|
|
1036
|
+
id: nil,
|
|
1037
|
+
status: nil,
|
|
1038
|
+
queue: nil,
|
|
1039
|
+
type: nil,
|
|
1040
|
+
filter: nil,
|
|
1041
|
+
priority: nil,
|
|
1042
|
+
ready_at: nil,
|
|
1043
|
+
attempts: nil
|
|
1044
|
+
)
|
|
981
1045
|
{
|
|
982
1046
|
id:,
|
|
983
1047
|
status:,
|
|
@@ -986,7 +1050,7 @@ module Zizq
|
|
|
986
1050
|
filter:,
|
|
987
1051
|
priority: encode_range(priority),
|
|
988
1052
|
ready_at: encode_range(ready_at) { |v| (v.to_f * 1000).to_i },
|
|
989
|
-
attempts: encode_range(attempts)
|
|
1053
|
+
attempts: encode_range(attempts)
|
|
990
1054
|
}.compact
|
|
991
1055
|
end
|
|
992
1056
|
|
|
@@ -1016,7 +1080,7 @@ module Zizq
|
|
|
1016
1080
|
when Range
|
|
1017
1081
|
if value.exclude_end?
|
|
1018
1082
|
raise ArgumentError,
|
|
1019
|
-
|
|
1083
|
+
"exclusive ranges are not supported by the server; use an inclusive range (a..b) instead"
|
|
1020
1084
|
end
|
|
1021
1085
|
"#{value.begin&.then(&block)}..#{value.end&.then(&block)}"
|
|
1022
1086
|
else
|
|
@@ -1034,13 +1098,22 @@ module Zizq
|
|
|
1034
1098
|
# @rbs backoff: (Zizq::backoff | singleton(Zizq::RESET) | singleton(Zizq::UNCHANGED))?
|
|
1035
1099
|
# @rbs retention: (Zizq::retention | singleton(Zizq::RESET) | singleton(Zizq::UNCHANGED))?
|
|
1036
1100
|
# @rbs return: Hash[Symbol, untyped]
|
|
1037
|
-
def validate_and_build_set(
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1101
|
+
def validate_and_build_set(
|
|
1102
|
+
queue: UNCHANGED,
|
|
1103
|
+
priority: UNCHANGED,
|
|
1104
|
+
ready_at: UNCHANGED,
|
|
1105
|
+
retry_limit: UNCHANGED,
|
|
1106
|
+
backoff: UNCHANGED,
|
|
1107
|
+
retention: UNCHANGED
|
|
1108
|
+
)
|
|
1109
|
+
build_set_body(
|
|
1110
|
+
queue:,
|
|
1111
|
+
priority:,
|
|
1112
|
+
ready_at:,
|
|
1113
|
+
retry_limit:,
|
|
1114
|
+
backoff:,
|
|
1115
|
+
retention:
|
|
1116
|
+
)
|
|
1044
1117
|
end
|
|
1045
1118
|
|
|
1046
1119
|
# Build the JSON body hash for a PATCH request from set parameters.
|
|
@@ -1051,26 +1124,40 @@ module Zizq
|
|
|
1051
1124
|
# - Other values are converted to their wire format.
|
|
1052
1125
|
#
|
|
1053
1126
|
# @rbs return: Hash[Symbol, untyped]
|
|
1054
|
-
def build_set_body(
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1127
|
+
def build_set_body(
|
|
1128
|
+
queue: UNCHANGED,
|
|
1129
|
+
priority: UNCHANGED,
|
|
1130
|
+
ready_at: UNCHANGED,
|
|
1131
|
+
retry_limit: UNCHANGED,
|
|
1132
|
+
backoff: UNCHANGED,
|
|
1133
|
+
retention: UNCHANGED
|
|
1134
|
+
)
|
|
1060
1135
|
body = {} #: Hash[Symbol, untyped]
|
|
1061
1136
|
|
|
1062
1137
|
unless queue.equal?(UNCHANGED)
|
|
1063
|
-
|
|
1138
|
+
if queue.nil?
|
|
1139
|
+
raise ArgumentError,
|
|
1140
|
+
"queue cannot be nil; use Zizq::RESET to clear or Zizq::UNCHANGED to leave as-is"
|
|
1141
|
+
end
|
|
1064
1142
|
body[:queue] = queue
|
|
1065
1143
|
end
|
|
1066
1144
|
|
|
1067
1145
|
unless priority.equal?(UNCHANGED)
|
|
1068
|
-
|
|
1146
|
+
if priority.nil?
|
|
1147
|
+
raise ArgumentError,
|
|
1148
|
+
"priority cannot be nil; use Zizq::RESET to clear or Zizq::UNCHANGED to leave as-is"
|
|
1149
|
+
end
|
|
1069
1150
|
body[:priority] = priority
|
|
1070
1151
|
end
|
|
1071
1152
|
|
|
1072
1153
|
unless ready_at.equal?(UNCHANGED)
|
|
1073
|
-
body[:ready_at] =
|
|
1154
|
+
body[:ready_at] = (
|
|
1155
|
+
if ready_at.equal?(RESET)
|
|
1156
|
+
nil
|
|
1157
|
+
else
|
|
1158
|
+
(ready_at.to_f * 1000).to_i
|
|
1159
|
+
end
|
|
1160
|
+
)
|
|
1074
1161
|
end
|
|
1075
1162
|
|
|
1076
1163
|
unless retry_limit.equal?(UNCHANGED)
|
|
@@ -1094,8 +1181,12 @@ module Zizq
|
|
|
1094
1181
|
nil
|
|
1095
1182
|
else
|
|
1096
1183
|
ret = {} #: Hash[Symbol, Integer]
|
|
1097
|
-
ret[:completed_ms] = (
|
|
1098
|
-
|
|
1184
|
+
ret[:completed_ms] = (
|
|
1185
|
+
retention[:completed].to_f * 1000
|
|
1186
|
+
).to_i if retention[:completed]
|
|
1187
|
+
ret[:dead_ms] = (retention[:dead].to_f * 1000).to_i if retention[
|
|
1188
|
+
:dead
|
|
1189
|
+
]
|
|
1099
1190
|
ret
|
|
1100
1191
|
end
|
|
1101
1192
|
end
|
|
@@ -1118,22 +1209,32 @@ module Zizq
|
|
|
1118
1209
|
|
|
1119
1210
|
def encode_body(body) #: (Hash[Symbol, untyped]) -> String
|
|
1120
1211
|
case @format
|
|
1121
|
-
when :msgpack
|
|
1122
|
-
|
|
1123
|
-
|
|
1212
|
+
when :msgpack
|
|
1213
|
+
MessagePack.pack(body)
|
|
1214
|
+
when :json
|
|
1215
|
+
JSON.generate(body)
|
|
1216
|
+
else
|
|
1217
|
+
raise ArgumentError, "Unknown format: #{@format}"
|
|
1124
1218
|
end
|
|
1125
1219
|
end
|
|
1126
1220
|
|
|
1127
1221
|
def decode_body(data, content_type: nil) #: (String, ?content_type: String?) -> Hash[String, untyped]
|
|
1128
|
-
format =
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1222
|
+
format =
|
|
1223
|
+
case content_type
|
|
1224
|
+
when /msgpack/
|
|
1225
|
+
:msgpack
|
|
1226
|
+
when /json/
|
|
1227
|
+
:json
|
|
1228
|
+
else
|
|
1229
|
+
@format
|
|
1230
|
+
end
|
|
1133
1231
|
case format
|
|
1134
|
-
when :msgpack
|
|
1135
|
-
|
|
1136
|
-
|
|
1232
|
+
when :msgpack
|
|
1233
|
+
MessagePack.unpack(data)
|
|
1234
|
+
when :json
|
|
1235
|
+
JSON.parse(data)
|
|
1236
|
+
else
|
|
1237
|
+
raise ArgumentError, "Unknown format: #{format}"
|
|
1137
1238
|
end
|
|
1138
1239
|
end
|
|
1139
1240
|
|
|
@@ -1153,7 +1254,11 @@ module Zizq
|
|
|
1153
1254
|
# Read the response body and close it, returning a RawResponse that is
|
|
1154
1255
|
# safe to use outside the reactor.
|
|
1155
1256
|
def consume_response(response) #: (untyped) -> RawResponse
|
|
1156
|
-
RawResponse.new(
|
|
1257
|
+
RawResponse.new(
|
|
1258
|
+
status: response.status,
|
|
1259
|
+
body: response.read,
|
|
1260
|
+
content_type: response.headers["content-type"]
|
|
1261
|
+
)
|
|
1157
1262
|
ensure
|
|
1158
1263
|
response.close
|
|
1159
1264
|
end
|
|
@@ -1239,24 +1344,22 @@ module Zizq
|
|
|
1239
1344
|
end
|
|
1240
1345
|
|
|
1241
1346
|
def thread_local_http(key, endpoint) #: (Symbol, Async::HTTP::Endpoint) -> Async::HTTP::Client
|
|
1242
|
-
Thread.current.thread_variable_get(key) ||
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
@
|
|
1246
|
-
|
|
1347
|
+
Thread.current.thread_variable_get(key) ||
|
|
1348
|
+
begin
|
|
1349
|
+
client = Async::HTTP::Client.new(endpoint)
|
|
1350
|
+
@mutex.synchronize do
|
|
1351
|
+
@http_clients.reject! { |ref| !ref.weakref_alive? }
|
|
1352
|
+
@http_clients << WeakRef.new(client)
|
|
1353
|
+
end
|
|
1354
|
+
Thread.current.thread_variable_set(key, client)
|
|
1355
|
+
client
|
|
1247
1356
|
end
|
|
1248
|
-
Thread.current.thread_variable_set(key, client)
|
|
1249
|
-
client
|
|
1250
|
-
end
|
|
1251
1357
|
end
|
|
1252
1358
|
|
|
1253
1359
|
def get(path, params: {}) #: (String, ?params: Hash[Symbol, untyped]) -> RawResponse
|
|
1254
1360
|
request do |http|
|
|
1255
1361
|
consume_response(
|
|
1256
|
-
http.get(
|
|
1257
|
-
build_path(path, params:),
|
|
1258
|
-
{"accept" => @content_type}
|
|
1259
|
-
)
|
|
1362
|
+
http.get(build_path(path, params:), { "accept" => @content_type })
|
|
1260
1363
|
)
|
|
1261
1364
|
end
|
|
1262
1365
|
end
|
|
@@ -1266,7 +1369,7 @@ module Zizq
|
|
|
1266
1369
|
consume_response(
|
|
1267
1370
|
http.post(
|
|
1268
1371
|
build_path(path),
|
|
1269
|
-
{"content-type" => @content_type, "accept" => @content_type},
|
|
1372
|
+
{ "content-type" => @content_type, "accept" => @content_type },
|
|
1270
1373
|
Protocol::HTTP::Body::Buffered.wrap(encode_body(body))
|
|
1271
1374
|
)
|
|
1272
1375
|
)
|
|
@@ -1276,10 +1379,7 @@ module Zizq
|
|
|
1276
1379
|
def raw_post(path) #: (String) -> RawResponse
|
|
1277
1380
|
request do |http|
|
|
1278
1381
|
consume_response(
|
|
1279
|
-
http.post(
|
|
1280
|
-
build_path(path),
|
|
1281
|
-
{"accept" => @content_type}
|
|
1282
|
-
)
|
|
1382
|
+
http.post(build_path(path), { "accept" => @content_type })
|
|
1283
1383
|
)
|
|
1284
1384
|
end
|
|
1285
1385
|
end
|
|
@@ -1289,7 +1389,7 @@ module Zizq
|
|
|
1289
1389
|
consume_response(
|
|
1290
1390
|
http.put(
|
|
1291
1391
|
build_path(path),
|
|
1292
|
-
{"content-type" => @content_type, "accept" => @content_type},
|
|
1392
|
+
{ "content-type" => @content_type, "accept" => @content_type },
|
|
1293
1393
|
Protocol::HTTP::Body::Buffered.wrap(encode_body(body))
|
|
1294
1394
|
)
|
|
1295
1395
|
)
|
|
@@ -1299,10 +1399,7 @@ module Zizq
|
|
|
1299
1399
|
def delete(path, params: {}) #: (String, ?params: Hash[Symbol, untyped]) -> RawResponse
|
|
1300
1400
|
request do |http|
|
|
1301
1401
|
consume_response(
|
|
1302
|
-
http.delete(
|
|
1303
|
-
build_path(path, params:),
|
|
1304
|
-
{"accept" => @content_type}
|
|
1305
|
-
)
|
|
1402
|
+
http.delete(build_path(path, params:), { "accept" => @content_type })
|
|
1306
1403
|
)
|
|
1307
1404
|
end
|
|
1308
1405
|
end
|
|
@@ -1312,7 +1409,7 @@ module Zizq
|
|
|
1312
1409
|
consume_response(
|
|
1313
1410
|
http.patch(
|
|
1314
1411
|
build_path(path, params:),
|
|
1315
|
-
{"content-type" => @content_type, "accept" => @content_type},
|
|
1412
|
+
{ "content-type" => @content_type, "accept" => @content_type },
|
|
1316
1413
|
Protocol::HTTP::Body::Buffered.wrap(encode_body(body))
|
|
1317
1414
|
)
|
|
1318
1415
|
)
|
|
@@ -1330,18 +1427,24 @@ module Zizq
|
|
|
1330
1427
|
return nil if status == 204
|
|
1331
1428
|
decode_body(response.body, content_type: ct)
|
|
1332
1429
|
else
|
|
1333
|
-
body =
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1430
|
+
body =
|
|
1431
|
+
begin
|
|
1432
|
+
decode_body(response.body, content_type: ct)
|
|
1433
|
+
rescue StandardError
|
|
1434
|
+
nil
|
|
1435
|
+
end
|
|
1338
1436
|
message = body&.fetch("error", nil) || "HTTP #{status}"
|
|
1339
|
-
error_class =
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1437
|
+
error_class =
|
|
1438
|
+
case status
|
|
1439
|
+
when 404
|
|
1440
|
+
NotFoundError
|
|
1441
|
+
when 400..499
|
|
1442
|
+
ClientError
|
|
1443
|
+
when 500..599
|
|
1444
|
+
ServerError
|
|
1445
|
+
else
|
|
1446
|
+
ResponseError
|
|
1447
|
+
end
|
|
1345
1448
|
raise error_class.new(message, status: status, body: body)
|
|
1346
1449
|
end
|
|
1347
1450
|
end
|