postjob 0.5.9 → 0.5.10
Sign up to get free protection for your applications and to get access to all the features.
- 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")
|