postjob 0.5.9 → 0.5.10
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/postjob/cli/enqueue.rb +1 -1
- data/lib/postjob/cli/ps.rb +15 -10
- data/lib/postjob/cli/run.rb +4 -2
- data/lib/postjob/cli.rb +2 -0
- data/lib/postjob/job.rb +2 -0
- data/lib/postjob/migrations/013a_checkout_runnable.sql +11 -3
- data/lib/postjob/queue/notifications.rb +7 -4
- data/lib/postjob/queue.rb +7 -2
- data/lib/postjob/registry.rb +1 -1
- data/lib/postjob/runner.rb +6 -3
- data/lib/postjob/workflow.rb +2 -2
- data/lib/postjob.rb +26 -5
- data/spec/postjob/enqueue_spec.rb +4 -4
- data/spec/postjob/run_spec.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a27daa3a8a98739c5b78fe5b74cab7fb9f8d16b
|
|
4
|
+
data.tar.gz: 41eab0fe1314594cbeaaa06b364e476855f7839c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f89717293ad0920aef170e08a9fbca783e95d509c47153c2e217f9d13f445eb49725b84d349aa1e868858f4a53584f1247e3b0934ceec88ec63ff1e0e37c5f22
|
|
7
|
+
data.tar.gz: c600c26793d24e26f51626b0de1e7c741fe0cb11db3f85562f6308ae2184738cd82bdef7d9b8a0bdcb9841987f1b1186c37fddac89a7cc343de0adf5239f1688
|
data/lib/postjob/cli/enqueue.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Postjob::CLI
|
|
|
6
6
|
#
|
|
7
7
|
# Note that the workflow will receive the arguments as strings and must be
|
|
8
8
|
# prepared to handle these.
|
|
9
|
-
def enqueue(workflow, *args, queue:
|
|
9
|
+
def enqueue(workflow, *args, queue: nil, tags: nil)
|
|
10
10
|
connect_to_database!
|
|
11
11
|
|
|
12
12
|
Postjob.enqueue! workflow, *args, queue: queue, tags: parse_tags(tags)
|
data/lib/postjob/cli/ps.rb
CHANGED
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
module Postjob::CLI
|
|
7
7
|
private
|
|
8
8
|
|
|
9
|
-
def ps_query(tags:, limit:)
|
|
9
|
+
def ps_query(tags:, limit:, queue:)
|
|
10
10
|
limit = Integer(limit)
|
|
11
11
|
|
|
12
12
|
sql = <<-SQL
|
|
13
13
|
SELECT
|
|
14
14
|
postjobs.id,
|
|
15
15
|
full_id,
|
|
16
|
+
postjobs.queue,
|
|
16
17
|
workflow
|
|
17
18
|
|| (CASE WHEN workflow_version != '' THEN '@' ELSE '' END)
|
|
18
19
|
|| workflow_version
|
|
@@ -27,7 +28,7 @@ module Postjob::CLI
|
|
|
27
28
|
max_attempts,
|
|
28
29
|
cron_interval AS cron,
|
|
29
30
|
CASE
|
|
30
|
-
WHEN is_sticky THEN COALESCE(sticky_host_id::varchar, 'yes')
|
|
31
|
+
WHEN is_sticky THEN COALESCE(substring(sticky_host_id::varchar for 6) || '...', 'yes')
|
|
31
32
|
ELSE 'no'
|
|
32
33
|
END AS sticky,
|
|
33
34
|
next_run_at,
|
|
@@ -40,6 +41,7 @@ module Postjob::CLI
|
|
|
40
41
|
|
|
41
42
|
scope = Simple::SQL::Scope.new(sql)
|
|
42
43
|
scope = scope.where("tags @> ?", Postjob::Queue::Encoder.encode(parse_tags(tags))) if tags
|
|
44
|
+
scope = scope.where(queue: queue) if queue
|
|
43
45
|
|
|
44
46
|
scope
|
|
45
47
|
.paginate(per: limit, page: 1)
|
|
@@ -59,9 +61,10 @@ module Postjob::CLI
|
|
|
59
61
|
#
|
|
60
62
|
# For a listing of all jobs in the system use ps:full, see 'postjob help ps:full'
|
|
61
63
|
# for details.
|
|
62
|
-
def ps(*ids, limit: "100", tags: nil)
|
|
64
|
+
def ps(*ids, limit: "100", tags: nil, queue: nil)
|
|
63
65
|
expect! limit => /\A\d+\z/
|
|
64
66
|
limit = Integer(limit)
|
|
67
|
+
queue = queue.split(",") if queue
|
|
65
68
|
|
|
66
69
|
connect_to_database!
|
|
67
70
|
|
|
@@ -73,16 +76,18 @@ module Postjob::CLI
|
|
|
73
76
|
return
|
|
74
77
|
end
|
|
75
78
|
|
|
76
|
-
query = ps_query(tags: tags, limit: limit)
|
|
77
|
-
query = query.where("root_id=id OR status NOT IN ('
|
|
79
|
+
query = ps_query(tags: tags, limit: limit, queue: queue)
|
|
80
|
+
query = query.where("root_id=id OR status NOT IN ('sleep', 'ok') OR failed_attempts > 0")
|
|
78
81
|
|
|
79
82
|
print_results query: query
|
|
80
83
|
end
|
|
81
84
|
|
|
82
|
-
def ps_full(*ids, limit: "100", tags: nil)
|
|
85
|
+
def ps_full(*ids, limit: "100", tags: nil, queue: nil)
|
|
86
|
+
queue = queue.split(",") if queue
|
|
87
|
+
|
|
83
88
|
connect_to_database!
|
|
84
89
|
|
|
85
|
-
query = ps_query(tags: tags, limit: limit)
|
|
90
|
+
query = ps_query(tags: tags, limit: limit, queue: queue)
|
|
86
91
|
|
|
87
92
|
unless ids.empty?
|
|
88
93
|
parsed_ids = parse_ids(*ids)
|
|
@@ -93,13 +98,13 @@ module Postjob::CLI
|
|
|
93
98
|
end
|
|
94
99
|
|
|
95
100
|
# Show up-to-date information once per second
|
|
96
|
-
def ps_top(*ids, limit: "100", tags: nil, full: false)
|
|
101
|
+
def ps_top(*ids, limit: "100", tags: nil, full: false, queue: nil)
|
|
97
102
|
loop do
|
|
98
103
|
system "clear"
|
|
99
104
|
if full
|
|
100
|
-
ps_full(*ids, limit: limit, tags: tags)
|
|
105
|
+
ps_full(*ids, limit: limit, tags: tags, queue: queue)
|
|
101
106
|
else
|
|
102
|
-
ps(*ids, limit: limit, tags: tags)
|
|
107
|
+
ps(*ids, limit: limit, tags: tags, queue: queue)
|
|
103
108
|
end
|
|
104
109
|
sleep 1
|
|
105
110
|
end
|
data/lib/postjob/cli/run.rb
CHANGED
|
@@ -11,16 +11,18 @@ module Postjob::CLI
|
|
|
11
11
|
# Parameters:
|
|
12
12
|
#
|
|
13
13
|
# - count=<count> maximum number of jobs to process. Default: unlimited.
|
|
14
|
+
# - queue run only the specified queue.
|
|
14
15
|
# - quiet don't show progress.
|
|
15
16
|
#
|
|
16
|
-
def run(count: nil, quiet: false)
|
|
17
|
+
def run(count: nil, queue: nil, quiet: false)
|
|
17
18
|
count = Integer(count) if count
|
|
19
|
+
queue = queue.split(",") if queue
|
|
18
20
|
|
|
19
21
|
connect_to_database!
|
|
20
22
|
|
|
21
23
|
logger.success "Starting runner with pid #{$$}"
|
|
22
24
|
|
|
23
|
-
processed = Postjob.run(count: count) do |job_id|
|
|
25
|
+
processed = Postjob.run(count: count, queue: queue) do |job_id|
|
|
24
26
|
logger.info "Processed job w/id #{job_id}" if job_id
|
|
25
27
|
STDERR.print "." unless quiet
|
|
26
28
|
end
|
data/lib/postjob/cli.rb
CHANGED
data/lib/postjob/job.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
DROP FUNCTION IF EXISTS {SCHEMA_NAME}.time_to_next_job(workflows_with_versions varchar[]); -- removed in 0.5.0
|
|
2
|
-
|
|
2
|
+
DROP FUNCTION IF EXISTS {SCHEMA_NAME}.time_to_next_job(p_worker_session_id UUID); -- removed in 0.5.7
|
|
3
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.time_to_next_job(p_worker_session_id UUID, p_queue varchar[])
|
|
3
4
|
RETURNS float
|
|
4
5
|
AS $$
|
|
5
6
|
DECLARE
|
|
@@ -17,6 +18,7 @@ BEGIN
|
|
|
17
18
|
SELECT MIN(next_run_at) AS processable_at
|
|
18
19
|
FROM {SCHEMA_NAME}.postjobs
|
|
19
20
|
WHERE status IN ('ready', 'err')
|
|
21
|
+
AND (p_queue IS NULL OR queue = ANY (p_queue))
|
|
20
22
|
AND (workflow || workflow_version) = ANY (session.workflows)
|
|
21
23
|
AND COALESCE(sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid())
|
|
22
24
|
) sq;
|
|
@@ -26,7 +28,12 @@ END;
|
|
|
26
28
|
$$ LANGUAGE plpgsql;
|
|
27
29
|
|
|
28
30
|
DROP FUNCTION IF EXISTS {SCHEMA_NAME}.checkout(workflows_with_versions varchar[], p_fast_mode BOOLEAN); -- removed in 0.5.0
|
|
29
|
-
|
|
31
|
+
DROP FUNCTION IF EXISTS {SCHEMA_NAME}.checkout(p_worker_session_id UUID, p_fast_mode BOOLEAN); -- removed in 0.5.8
|
|
32
|
+
|
|
33
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.checkout(
|
|
34
|
+
p_worker_session_id UUID,
|
|
35
|
+
p_fast_mode BOOLEAN,
|
|
36
|
+
p_queue varchar[])
|
|
30
37
|
RETURNS SETOF {SCHEMA_NAME}.postjobs
|
|
31
38
|
AS $$
|
|
32
39
|
DECLARE
|
|
@@ -52,8 +59,9 @@ BEGIN
|
|
|
52
59
|
AND s.next_run_at <= (now() at time zone 'utc')
|
|
53
60
|
AND (s.workflow || s.workflow_version) = ANY (session.workflows)
|
|
54
61
|
AND COALESCE(s.sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid())
|
|
62
|
+
AND (p_queue IS NULL OR queue = ANY (p_queue))
|
|
55
63
|
)
|
|
56
|
-
ORDER BY (LEAST(s.next_run_at, s.timing_out_at))
|
|
64
|
+
ORDER BY (LEAST(CASE WHEN s.sticky_host_id IS NOT NULL THEN s.next_run_at - interval '180 seconds' ELSE s.next_run_at END, s.timing_out_at))
|
|
57
65
|
FOR UPDATE SKIP LOCKED
|
|
58
66
|
LIMIT 1;
|
|
59
67
|
|
|
@@ -8,14 +8,14 @@ module Postjob::Queue::Notifications
|
|
|
8
8
|
SCHEMA_NAME = ::Postjob::Queue::SCHEMA_NAME
|
|
9
9
|
MAX_WAIT_TIME = 120
|
|
10
10
|
|
|
11
|
-
def wait_for_new_job(worker_session_id)
|
|
11
|
+
def wait_for_new_job(worker_session_id, queue:)
|
|
12
12
|
started_at = Time.now
|
|
13
13
|
|
|
14
14
|
start_listening
|
|
15
15
|
|
|
16
16
|
# Determine when the next job is up. If we don't have a next job within MAX_WAIT_TIME
|
|
17
17
|
# we wake up regardless.
|
|
18
|
-
wait_time = time_to_next_job(worker_session_id)
|
|
18
|
+
wait_time = time_to_next_job(worker_session_id, queue: queue)
|
|
19
19
|
return if wait_time && wait_time <= 0
|
|
20
20
|
|
|
21
21
|
wait_time = MAX_WAIT_TIME if !wait_time || wait_time > MAX_WAIT_TIME
|
|
@@ -43,8 +43,11 @@ module Postjob::Queue::Notifications
|
|
|
43
43
|
|
|
44
44
|
# returns the maximum number of seconds to wait until the
|
|
45
45
|
# next runnable or timeoutable job comes up.
|
|
46
|
-
def time_to_next_job(worker_session_id)
|
|
46
|
+
def time_to_next_job(worker_session_id, queue:)
|
|
47
47
|
expect! worker_session_id => /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i
|
|
48
|
-
|
|
48
|
+
expect! queue => [ String, Array, nil ]
|
|
49
|
+
|
|
50
|
+
queue = Array(queue)
|
|
51
|
+
Simple::SQL.ask "SELECT * FROM #{SCHEMA_NAME}.time_to_next_job($1::uuid, $2)", worker_session_id, queue
|
|
49
52
|
end
|
|
50
53
|
end
|
data/lib/postjob/queue.rb
CHANGED
|
@@ -157,9 +157,14 @@ module Postjob::Queue
|
|
|
157
157
|
|
|
158
158
|
UUID_REGEXP = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i
|
|
159
159
|
|
|
160
|
-
def checkout(worker_session_id)
|
|
160
|
+
def checkout(worker_session_id, queue:)
|
|
161
161
|
expect! worker_session_id => UUID_REGEXP
|
|
162
|
-
|
|
162
|
+
expect! queue => [ nil, Array, String ]
|
|
163
|
+
|
|
164
|
+
queue = Array(queue) if queue
|
|
165
|
+
|
|
166
|
+
SQL.ask "SELECT * FROM #{SCHEMA_NAME}.checkout($1::uuid, $2::boolean, $3)",
|
|
167
|
+
worker_session_id, Postjob.fast_mode, queue, into: Job
|
|
163
168
|
end
|
|
164
169
|
|
|
165
170
|
def find_or_create_token(job)
|
data/lib/postjob/registry.rb
CHANGED
data/lib/postjob/runner.rb
CHANGED
|
@@ -35,9 +35,11 @@ module Postjob::Runner
|
|
|
35
35
|
|
|
36
36
|
# returns a subjob within the current job, for a +runner+
|
|
37
37
|
# description and +args+.
|
|
38
|
-
def async(workflow, *args, timeout: nil, max_attempts:)
|
|
38
|
+
def async(workflow, *args, timeout: nil, max_attempts: nil, queue: nil)
|
|
39
39
|
worker_session_id = Postjob.current_worker_session.id
|
|
40
40
|
|
|
41
|
+
queue = current_job.queue if queue.nil?
|
|
42
|
+
|
|
41
43
|
# if the workflow is a symbol, then we change it into "__manual__"
|
|
42
44
|
# - there should never be a workflow with that name - or into
|
|
43
45
|
# "CurrentWorkshop.#{workflow}", denoting the \a workflow method of the
|
|
@@ -52,12 +54,13 @@ module Postjob::Runner
|
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
::Postjob::Queue.find_or_create_childjob(worker_session_id, self.current_job, workflow, args,
|
|
57
|
+
queue: queue,
|
|
55
58
|
timeout: timeout,
|
|
56
59
|
max_attempts: max_attempts)
|
|
57
60
|
end
|
|
58
61
|
|
|
59
62
|
# tries to resolve a job.
|
|
60
|
-
def await(job, *args, timeout: nil, max_attempts: nil)
|
|
63
|
+
def await(job, *args, timeout: nil, max_attempts: nil, queue: nil)
|
|
61
64
|
case job
|
|
62
65
|
when :all
|
|
63
66
|
unresolved_childjobs = Postjob::Queue.unresolved_childjobs(current_job)
|
|
@@ -75,7 +78,7 @@ module Postjob::Runner
|
|
|
75
78
|
throw :pending, :pending if r == :pending
|
|
76
79
|
r
|
|
77
80
|
else
|
|
78
|
-
job = async(job, *args, timeout: timeout, max_attempts: max_attempts)
|
|
81
|
+
job = async(job, *args, timeout: timeout, max_attempts: max_attempts, queue: queue)
|
|
79
82
|
await(job)
|
|
80
83
|
end
|
|
81
84
|
end
|
data/lib/postjob/workflow.rb
CHANGED
|
@@ -15,8 +15,8 @@ module Postjob::Workflow
|
|
|
15
15
|
# we cannot run such a test.
|
|
16
16
|
|
|
17
17
|
# see Postjob::Runner.async
|
|
18
|
-
def async(runner, *args, timeout: nil, max_attempts: nil)
|
|
19
|
-
::Postjob::Runner.async(runner, *args, timeout: timeout, max_attempts: max_attempts)
|
|
18
|
+
def async(runner, *args, timeout: nil, max_attempts: nil, queue: nil)
|
|
19
|
+
::Postjob::Runner.async(runner, *args, timeout: timeout, max_attempts: max_attempts, queue: queue)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# see Postjob::Runner.await
|
data/lib/postjob.rb
CHANGED
|
@@ -49,6 +49,8 @@ module Postjob
|
|
|
49
49
|
# - cron_interval
|
|
50
50
|
# - queue
|
|
51
51
|
#
|
|
52
|
+
#
|
|
53
|
+
# Returns a job id
|
|
52
54
|
def enqueue!(workflow, *args, queue: nil,
|
|
53
55
|
parent_id: nil,
|
|
54
56
|
max_attempts: nil,
|
|
@@ -156,7 +158,7 @@ module Postjob
|
|
|
156
158
|
# b) the block yielded into returns false.
|
|
157
159
|
#
|
|
158
160
|
# This method returns the number of processed jobs.
|
|
159
|
-
def run(count: nil, &block)
|
|
161
|
+
def run(count: nil, queue: nil, &block)
|
|
160
162
|
# to run 10^12 jobs that would take 1 msecs each we would need, at least,
|
|
161
163
|
# 760 years - so this default should be fine. Also, someone should update
|
|
162
164
|
# the machine in the meantime :)
|
|
@@ -165,7 +167,7 @@ module Postjob
|
|
|
165
167
|
processed_jobs_count = 0
|
|
166
168
|
|
|
167
169
|
loop do
|
|
168
|
-
processed_job_id, shutdown = Postjob.step
|
|
170
|
+
processed_job_id, shutdown = Postjob.step(queue: queue)
|
|
169
171
|
processed_jobs_count += 1 if processed_job_id
|
|
170
172
|
|
|
171
173
|
break if processed_jobs_count >= count
|
|
@@ -173,7 +175,7 @@ module Postjob
|
|
|
173
175
|
break if shutdown == :shutdown
|
|
174
176
|
|
|
175
177
|
next if processed_job_id
|
|
176
|
-
Queue::Notifications.wait_for_new_job(current_worker_session.id)
|
|
178
|
+
Queue::Notifications.wait_for_new_job(current_worker_session.id, queue: queue)
|
|
177
179
|
end
|
|
178
180
|
|
|
179
181
|
processed_jobs_count
|
|
@@ -191,8 +193,9 @@ module Postjob
|
|
|
191
193
|
# self.run to terminate the run loop.
|
|
192
194
|
#
|
|
193
195
|
# or nil, when no job could be checked out.
|
|
194
|
-
def step
|
|
195
|
-
job = Postjob::Queue.checkout(current_worker_session.id)
|
|
196
|
+
def step(queue: nil)
|
|
197
|
+
job = Postjob::Queue.checkout(current_worker_session.id, queue: queue)
|
|
198
|
+
|
|
196
199
|
[ job.id, process_job(job) ] if job
|
|
197
200
|
end
|
|
198
201
|
|
|
@@ -251,6 +254,7 @@ module Postjob
|
|
|
251
254
|
def process_job(job) # :nodoc:
|
|
252
255
|
expect! job => Job
|
|
253
256
|
|
|
257
|
+
# ap job
|
|
254
258
|
version, status, value, shutdown = Runner.process_job(job)
|
|
255
259
|
|
|
256
260
|
expect! version => String
|
|
@@ -268,6 +272,23 @@ module Postjob
|
|
|
268
272
|
else raise ArgumentError, "Invalid status #{status.inspect}"
|
|
269
273
|
end
|
|
270
274
|
|
|
275
|
+
if (status == :ok || status == :failed) && job.workflow_method == "run"
|
|
276
|
+
Simple::SQL.transaction do
|
|
277
|
+
job_id = enqueue! "#{job.workflow}.cleanup", *job.args, queue: job.queue,
|
|
278
|
+
parent_id: nil,
|
|
279
|
+
max_attempts: nil,
|
|
280
|
+
timeout: nil,
|
|
281
|
+
version: version,
|
|
282
|
+
tags: job.tags,
|
|
283
|
+
cron_interval: nil,
|
|
284
|
+
sticky: job.is_sticky
|
|
285
|
+
|
|
286
|
+
if job.is_sticky
|
|
287
|
+
Simple::SQL.ask "UPDATE postjob.postjobs SET sticky_host_id=$1 WHERE id=$2", job.sticky_host_id, job_id
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
271
292
|
shutdown
|
|
272
293
|
end
|
|
273
294
|
end
|
|
@@ -53,10 +53,10 @@ describe "Postjob.enqueue!" do
|
|
|
53
53
|
expect(job2.args).to eq([])
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
it "sets queue" do
|
|
56
|
+
it "sets the queue to the default queue name ('ruby')" do
|
|
57
57
|
id1 = Postjob.enqueue! workflow_name
|
|
58
58
|
job1 = load_job id1
|
|
59
|
-
expect(job1.queue).to eq("
|
|
59
|
+
expect(job1.queue).to eq("ruby")
|
|
60
60
|
|
|
61
61
|
id1 = Postjob.enqueue! workflow_name, queue: "bla"
|
|
62
62
|
job1 = load_job id1
|
|
@@ -82,8 +82,8 @@ describe "Postjob.enqueue!" do
|
|
|
82
82
|
|
|
83
83
|
context "with invalid arguments" do
|
|
84
84
|
it "raises an error with missing args" do
|
|
85
|
-
expect { Postjob.enqueue! queue: "
|
|
86
|
-
expect { Postjob.enqueue! workflow: "
|
|
85
|
+
expect { Postjob.enqueue! queue: "ruby" }.to raise_error(ArgumentError)
|
|
86
|
+
expect { Postjob.enqueue! workflow: "ruby" }.to raise_error(ArgumentError)
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
it "raises an error with invalid args" do
|
data/spec/postjob/run_spec.rb
CHANGED
|
@@ -23,7 +23,7 @@ describe "Postjob.process_all" do
|
|
|
23
23
|
let!(:id) { Postjob.enqueue! "TwoLevelWorkflow" }
|
|
24
24
|
|
|
25
25
|
it "runs the job returning the result" do
|
|
26
|
-
expect(Postjob.process_all).to eq(
|
|
26
|
+
expect(Postjob.process_all).to eq(5)
|
|
27
27
|
processed_job = load_job(id)
|
|
28
28
|
expect(processed_job.status).to eq("ok")
|
|
29
29
|
expect(processed_job.resolve).to eq("my string")
|