postjob 0.5.10 → 0.5.11
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.rb +26 -17
- data/lib/postjob/cli/enqueue.rb +6 -2
- data/lib/postjob/cli/ps.rb +8 -5
- data/lib/postjob/cli/run.rb +3 -1
- data/lib/postjob/migrations/003_postjobs.sql +10 -0
- data/lib/postjob/migrations/006_enqueue.sql +22 -4
- data/lib/postjob/migrations/008a_childjobs.sql +3 -2
- data/lib/postjob/migrations/013a_checkout_runnable.sql +38 -3
- data/lib/postjob/migrations/023_sticky_jobs.sql +8 -0
- data/lib/postjob/queue.rb +9 -3
- data/lib/postjob/registry.rb +26 -0
- data/lib/postjob/runner.rb +5 -0
- data/spec/postjob/run_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e26be7454c3a0ddb3d26d67b4e51918e8e16e306
|
|
4
|
+
data.tar.gz: f837746f80bba5cebbdd0fea7c7ad7c26eacbc5b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 361995efdeda5d1ca51de93c0807e37737581c32f53c25f20dc45c50c65dc008260abccc0d421776d59186997071fd2aa14cc23828f95145de6536bcf7859589
|
|
7
|
+
data.tar.gz: f374453e87325c9ddb05d4b1cad18f20d26b3a6c64a596de23ab471bc6bbc57017b20df5c589944e1cc90994ad717e4d1e57b7fa8ec6ab953ef48e6ec0a33adc
|
data/lib/postjob.rb
CHANGED
|
@@ -88,6 +88,7 @@ module Postjob
|
|
|
88
88
|
sticky = spec.options.sticky if sticky.nil?
|
|
89
89
|
cron_interval = spec.options.cron_interval if cron_interval.nil?
|
|
90
90
|
queue = spec.options.queue if queue.nil?
|
|
91
|
+
greedy = spec.options.greedy
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
if cron_interval && cron_interval < 300
|
|
@@ -111,7 +112,8 @@ module Postjob
|
|
|
111
112
|
tags: tags,
|
|
112
113
|
version: version,
|
|
113
114
|
cron_interval: cron_interval,
|
|
114
|
-
sticky: sticky
|
|
115
|
+
sticky: sticky,
|
|
116
|
+
greedy: greedy
|
|
115
117
|
|
|
116
118
|
logger.info "Generated process #{job}"
|
|
117
119
|
job.id
|
|
@@ -272,23 +274,30 @@ module Postjob
|
|
|
272
274
|
else raise ArgumentError, "Invalid status #{status.inspect}"
|
|
273
275
|
end
|
|
274
276
|
|
|
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
|
|
277
|
+
enqueue_cleanup(job) if (status == :ok || status == :failed) && job.workflow_method == "run"
|
|
291
278
|
|
|
292
279
|
shutdown
|
|
293
280
|
end
|
|
281
|
+
|
|
282
|
+
def enqueue_cleanup(job)
|
|
283
|
+
spec = Postjob::Registry.lookup!(name: job.workflow, version: job.workflow_version)
|
|
284
|
+
return unless spec.supports_cleanup?
|
|
285
|
+
|
|
286
|
+
Postjob.logger.info "Enqueuing cleanup job #{spec.name}.cleanup(#{job.args.map(&:inspect).join(", ")})"
|
|
287
|
+
|
|
288
|
+
Simple::SQL.transaction do
|
|
289
|
+
job_id = enqueue! "#{job.workflow}.cleanup", *job.args, queue: job.queue,
|
|
290
|
+
parent_id: nil,
|
|
291
|
+
max_attempts: nil,
|
|
292
|
+
timeout: nil,
|
|
293
|
+
version: job.workflow_version,
|
|
294
|
+
tags: job.tags,
|
|
295
|
+
cron_interval: nil,
|
|
296
|
+
sticky: job.is_sticky
|
|
297
|
+
|
|
298
|
+
if job.is_sticky
|
|
299
|
+
Simple::SQL.ask "UPDATE postjob.postjobs SET sticky_host_id=$1 WHERE id=$2", job.sticky_host_id, job_id
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
294
303
|
end
|
data/lib/postjob/cli/enqueue.rb
CHANGED
|
@@ -6,9 +6,13 @@ 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: nil, tags: nil)
|
|
9
|
+
def enqueue(workflow, *args, queue: nil, tags: nil, count: "1")
|
|
10
|
+
count = Integer(count)
|
|
11
|
+
|
|
10
12
|
connect_to_database!
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
count.times do
|
|
15
|
+
Postjob.enqueue! workflow, *args, queue: queue, tags: parse_tags(tags)
|
|
16
|
+
end
|
|
13
17
|
end
|
|
14
18
|
end
|
data/lib/postjob/cli/ps.rb
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
# rubocop:disable Metrics/MethodLength
|
|
3
3
|
# rubocop:disable Metrics/ModuleLength
|
|
4
4
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
5
|
+
# rubocop:disable Metrics/ParameterLists
|
|
5
6
|
|
|
6
7
|
module Postjob::CLI
|
|
7
8
|
private
|
|
8
9
|
|
|
9
|
-
def ps_query(tags:, limit:, queue:)
|
|
10
|
+
def ps_query(tags:, limit:, queue:, only_root: false)
|
|
10
11
|
limit = Integer(limit)
|
|
11
12
|
|
|
12
13
|
sql = <<-SQL
|
|
@@ -31,6 +32,7 @@ module Postjob::CLI
|
|
|
31
32
|
WHEN is_sticky THEN COALESCE(substring(sticky_host_id::varchar for 6) || '...', 'yes')
|
|
32
33
|
ELSE 'no'
|
|
33
34
|
END AS sticky,
|
|
35
|
+
is_greedy AS greedy,
|
|
34
36
|
next_run_at,
|
|
35
37
|
to_char(EXTRACT(EPOCH FROM (next_run_at - now() at time zone 'utc')), '999999999.99') AS next_run_in,
|
|
36
38
|
to_char(EXTRACT(EPOCH FROM (now() at time zone 'utc' - postjobs.created_at)), '999999999.99') AS age,
|
|
@@ -42,6 +44,7 @@ module Postjob::CLI
|
|
|
42
44
|
scope = Simple::SQL::Scope.new(sql)
|
|
43
45
|
scope = scope.where("tags @> ?", Postjob::Queue::Encoder.encode(parse_tags(tags))) if tags
|
|
44
46
|
scope = scope.where(queue: queue) if queue
|
|
47
|
+
scope = scope.where("id = root_id") if only_root
|
|
45
48
|
|
|
46
49
|
scope
|
|
47
50
|
.paginate(per: limit, page: 1)
|
|
@@ -61,7 +64,7 @@ module Postjob::CLI
|
|
|
61
64
|
#
|
|
62
65
|
# For a listing of all jobs in the system use ps:full, see 'postjob help ps:full'
|
|
63
66
|
# for details.
|
|
64
|
-
def ps(*ids, limit: "100", tags: nil, queue: nil)
|
|
67
|
+
def ps(*ids, limit: "100", tags: nil, queue: nil, only_root: nil)
|
|
65
68
|
expect! limit => /\A\d+\z/
|
|
66
69
|
limit = Integer(limit)
|
|
67
70
|
queue = queue.split(",") if queue
|
|
@@ -76,7 +79,7 @@ module Postjob::CLI
|
|
|
76
79
|
return
|
|
77
80
|
end
|
|
78
81
|
|
|
79
|
-
query = ps_query(tags: tags, limit: limit, queue: queue)
|
|
82
|
+
query = ps_query(tags: tags, limit: limit, queue: queue, only_root: only_root)
|
|
80
83
|
query = query.where("root_id=id OR status NOT IN ('sleep', 'ok') OR failed_attempts > 0")
|
|
81
84
|
|
|
82
85
|
print_results query: query
|
|
@@ -98,13 +101,13 @@ module Postjob::CLI
|
|
|
98
101
|
end
|
|
99
102
|
|
|
100
103
|
# Show up-to-date information once per second
|
|
101
|
-
def ps_top(*ids, limit: "100", tags: nil, full: false, queue: nil)
|
|
104
|
+
def ps_top(*ids, limit: "100", tags: nil, full: false, queue: nil, only_root: false)
|
|
102
105
|
loop do
|
|
103
106
|
system "clear"
|
|
104
107
|
if full
|
|
105
108
|
ps_full(*ids, limit: limit, tags: tags, queue: queue)
|
|
106
109
|
else
|
|
107
|
-
ps(*ids, limit: limit, tags: tags, queue: queue)
|
|
110
|
+
ps(*ids, limit: limit, tags: tags, queue: queue, only_root: only_root)
|
|
108
111
|
end
|
|
109
112
|
sleep 1
|
|
110
113
|
end
|
data/lib/postjob/cli/run.rb
CHANGED
|
@@ -14,10 +14,12 @@ module Postjob::CLI
|
|
|
14
14
|
# - queue run only the specified queue.
|
|
15
15
|
# - quiet don't show progress.
|
|
16
16
|
#
|
|
17
|
-
def run(count: nil, queue: nil, quiet: false)
|
|
17
|
+
def run(count: nil, queue: nil, quiet: false, fast: false)
|
|
18
18
|
count = Integer(count) if count
|
|
19
19
|
queue = queue.split(",") if queue
|
|
20
20
|
|
|
21
|
+
Postjob.fast_mode = (fast ? true : false)
|
|
22
|
+
|
|
21
23
|
connect_to_database!
|
|
22
24
|
|
|
23
25
|
logger.success "Starting runner with pid #{$$}"
|
|
@@ -63,6 +63,16 @@ CREATE TABLE IF NOT EXISTS {SCHEMA_NAME}.postjobs (
|
|
|
63
63
|
-- processing_max_duration float -- maximum expected duration of processing. Afterwards the
|
|
64
64
|
-- processing is considered failed for unknown reasons, and
|
|
65
65
|
-- potentially restarted.
|
|
66
|
+
|
|
67
|
+
-- process information ------------------------------------------------------------------------
|
|
68
|
+
--
|
|
69
|
+
-- Initially these columns didn't exist, and have been created via another migration.
|
|
70
|
+
|
|
71
|
+
-- last_worker_session_id uuid NOT NULL, -- session_id of last worker that touched this job
|
|
72
|
+
-- cron_interval integer, -- for cron jobs: cron_interval in seconds
|
|
73
|
+
-- is_sticky boolean DEFAULT false NOT NULL, -- when set this job is supposed to be sticky
|
|
74
|
+
-- sticky_host_id uuid -- once a sticky job starts running the job's host id
|
|
75
|
+
-- is_greedy boolean DEFAULT false NOT NULL -- is this a greedy job? (i.e. sticky, and do not allow any other job in this worker.)
|
|
66
76
|
);
|
|
67
77
|
|
|
68
78
|
-- [TODO] check indices
|
|
@@ -23,6 +23,20 @@ DROP FUNCTION IF EXISTS {SCHEMA_NAME}.enqueue(
|
|
|
23
23
|
timeout DOUBLE PRECISION,
|
|
24
24
|
p_cron_interval integer);
|
|
25
25
|
|
|
26
|
+
DROP FUNCTION IF EXISTS {SCHEMA_NAME}.enqueue(
|
|
27
|
+
p_worker_session_id UUID,
|
|
28
|
+
queue VARCHAR,
|
|
29
|
+
workflow VARCHAR,
|
|
30
|
+
workflow_method VARCHAR,
|
|
31
|
+
workflow_version VARCHAR,
|
|
32
|
+
args JSONB,
|
|
33
|
+
parent_id BIGINT,
|
|
34
|
+
tags JSONB,
|
|
35
|
+
max_attempts INTEGER,
|
|
36
|
+
timeout DOUBLE PRECISION,
|
|
37
|
+
p_cron_interval INTEGER,
|
|
38
|
+
p_is_sticky BOOLEAN);
|
|
39
|
+
|
|
26
40
|
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.enqueue(
|
|
27
41
|
p_worker_session_id UUID,
|
|
28
42
|
queue VARCHAR,
|
|
@@ -35,7 +49,8 @@ CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.enqueue(
|
|
|
35
49
|
max_attempts INTEGER,
|
|
36
50
|
timeout DOUBLE PRECISION,
|
|
37
51
|
p_cron_interval INTEGER,
|
|
38
|
-
p_is_sticky BOOLEAN
|
|
52
|
+
p_is_sticky BOOLEAN,
|
|
53
|
+
p_is_greedy BOOLEAN)
|
|
39
54
|
RETURNS SETOF {SCHEMA_NAME}.postjobs
|
|
40
55
|
AS $$
|
|
41
56
|
DECLARE
|
|
@@ -62,7 +77,8 @@ AS $$
|
|
|
62
77
|
workflow_version := COALESCE(workflow_version, '');
|
|
63
78
|
queue := COALESCE(queue, 'q');
|
|
64
79
|
max_attempts := COALESCE(max_attempts, 5);
|
|
65
|
-
|
|
80
|
+
p_is_greedy := COALESCE(p_is_greedy, FALSE);
|
|
81
|
+
p_is_sticky := p_is_greedy OR COALESCE(p_is_sticky, FALSE);
|
|
66
82
|
|
|
67
83
|
-- create postjobs entry ------------------------------------------
|
|
68
84
|
INSERT INTO {SCHEMA_NAME}.postjobs (
|
|
@@ -71,7 +87,8 @@ AS $$
|
|
|
71
87
|
parent_id, tags, max_attempts,
|
|
72
88
|
timing_out_at,
|
|
73
89
|
cron_interval,
|
|
74
|
-
is_sticky
|
|
90
|
+
is_sticky,
|
|
91
|
+
is_greedy
|
|
75
92
|
)
|
|
76
93
|
VALUES(
|
|
77
94
|
p_worker_session_id,
|
|
@@ -79,7 +96,8 @@ AS $$
|
|
|
79
96
|
parent_id, tags, max_attempts,
|
|
80
97
|
(now() at time zone 'utc') + timeout * interval '1 second',
|
|
81
98
|
p_cron_interval,
|
|
82
|
-
p_is_sticky
|
|
99
|
+
p_is_sticky,
|
|
100
|
+
p_is_greedy
|
|
83
101
|
) RETURNING {SCHEMA_NAME}.postjobs.id INTO job_id;
|
|
84
102
|
|
|
85
103
|
-- fill in root_id and full_id ------------------------------------
|
|
@@ -72,10 +72,11 @@ BEGIN
|
|
|
72
72
|
v_args, -- args JSONB,
|
|
73
73
|
v_parent_id, -- parent_id BIGINT,
|
|
74
74
|
parent.tags, -- tags JSONB,
|
|
75
|
-
v_max_attempts,
|
|
75
|
+
COALESCE(v_max_attempts, parent.max_attempts), -- max_attempts INTEGER,
|
|
76
76
|
v_timeout, -- timeout
|
|
77
77
|
NULL, -- cron_interval,
|
|
78
|
-
parent.is_sticky
|
|
78
|
+
parent.is_sticky, -- is_sticky?,
|
|
79
|
+
parent.is_greedy -- is_greedy?,
|
|
79
80
|
);
|
|
80
81
|
|
|
81
82
|
UPDATE {SCHEMA_NAME}.postjobs
|
|
@@ -6,10 +6,18 @@ AS $$
|
|
|
6
6
|
DECLARE
|
|
7
7
|
p_processable_at timestamp;
|
|
8
8
|
session {SCHEMA_NAME}.worker_sessions;
|
|
9
|
+
p_current_greedy_job {SCHEMA_NAME}.postjobs;
|
|
9
10
|
BEGIN
|
|
10
11
|
SELECT * INTO session
|
|
11
12
|
FROM {SCHEMA_NAME}.worker_sessions WHERE id=p_worker_session_id;
|
|
12
13
|
|
|
14
|
+
SELECT * INTO p_current_greedy_job
|
|
15
|
+
FROM {SCHEMA_NAME}.postjobs WHERE
|
|
16
|
+
status NOT IN ('ok', 'failed') AND
|
|
17
|
+
id=root_id AND
|
|
18
|
+
is_greedy
|
|
19
|
+
LIMIT 1;
|
|
20
|
+
|
|
13
21
|
SELECT MIN(processable_at) INTO p_processable_at FROM (
|
|
14
22
|
SELECT MIN(timing_out_at) AS processable_at
|
|
15
23
|
FROM {SCHEMA_NAME}.postjobs
|
|
@@ -20,7 +28,12 @@ BEGIN
|
|
|
20
28
|
WHERE status IN ('ready', 'err')
|
|
21
29
|
AND (p_queue IS NULL OR queue = ANY (p_queue))
|
|
22
30
|
AND (workflow || workflow_version) = ANY (session.workflows)
|
|
23
|
-
AND COALESCE(sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid())
|
|
31
|
+
AND COALESCE(sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid()) -- matches sticky_host_id for started sticky jobs and _null_uuid for
|
|
32
|
+
-- non-started or non-sticky jobs against the host_id and _null_uuid
|
|
33
|
+
AND (
|
|
34
|
+
p_current_greedy_job.id IS NULL OR root_id=p_current_greedy_job.root_id -- if there is a greedy job on this host_id which is not finished yet,
|
|
35
|
+
-- only jobs belonging to this root jobs are allowed.
|
|
36
|
+
)
|
|
24
37
|
) sq;
|
|
25
38
|
|
|
26
39
|
RETURN EXTRACT(EPOCH FROM p_processable_at - (now() at time zone 'utc'));
|
|
@@ -39,10 +52,28 @@ AS $$
|
|
|
39
52
|
DECLARE
|
|
40
53
|
job {SCHEMA_NAME}.postjobs;
|
|
41
54
|
session {SCHEMA_NAME}.worker_sessions;
|
|
55
|
+
p_current_greedy_job {SCHEMA_NAME}.postjobs;
|
|
42
56
|
BEGIN
|
|
43
57
|
SELECT * INTO session
|
|
44
58
|
FROM {SCHEMA_NAME}.worker_sessions WHERE id=p_worker_session_id;
|
|
45
59
|
|
|
60
|
+
--
|
|
61
|
+
-- We don't want multiple sessions to run this function in parallel. This can lead to a situation
|
|
62
|
+
-- where multiple greedy root jobs could be selected for different workers with identical host ids
|
|
63
|
+
-- at the same time. We therefore lock the function here against parallel usage - and we use the
|
|
64
|
+
-- hosts table for locking. This look will be released automatically with the current transaction,
|
|
65
|
+
-- i.e. typically after the "SELECT * FROM checkout(..)" returns.
|
|
66
|
+
--
|
|
67
|
+
PERFORM * FROM {SCHEMA_NAME}.hosts WHERE id=session.host_id FOR UPDATE;
|
|
68
|
+
|
|
69
|
+
SELECT * INTO p_current_greedy_job
|
|
70
|
+
FROM {SCHEMA_NAME}.postjobs WHERE
|
|
71
|
+
status NOT IN ('ok', 'failed')
|
|
72
|
+
AND id=root_id
|
|
73
|
+
AND sticky_host_id=session.host_id
|
|
74
|
+
AND is_greedy
|
|
75
|
+
LIMIT 1;
|
|
76
|
+
|
|
46
77
|
LOOP
|
|
47
78
|
-- try to checkout a job. Each of the conditions here is matching
|
|
48
79
|
-- one of the CASE .. WHEN clauses below.
|
|
@@ -56,12 +87,16 @@ BEGIN
|
|
|
56
87
|
OR
|
|
57
88
|
(
|
|
58
89
|
s.status IN ('ready', 'err')
|
|
90
|
+
AND (p_queue IS NULL OR queue = ANY (p_queue))
|
|
59
91
|
AND s.next_run_at <= (now() at time zone 'utc')
|
|
60
92
|
AND (s.workflow || s.workflow_version) = ANY (session.workflows)
|
|
61
93
|
AND COALESCE(s.sticky_host_id, {SCHEMA_NAME}._null_uuid()) IN (session.host_id, {SCHEMA_NAME}._null_uuid())
|
|
62
|
-
AND (
|
|
94
|
+
AND (
|
|
95
|
+
p_current_greedy_job.id IS NULL OR s.root_id=p_current_greedy_job.root_id -- if there is a greedy job on this host_id which is not finished yet,
|
|
96
|
+
-- only jobs belonging to this root jobs are allowed.
|
|
97
|
+
)
|
|
63
98
|
)
|
|
64
|
-
ORDER BY (LEAST(
|
|
99
|
+
ORDER BY (LEAST(s.next_run_at, s.timing_out_at))
|
|
65
100
|
FOR UPDATE SKIP LOCKED
|
|
66
101
|
LIMIT 1;
|
|
67
102
|
|
|
@@ -14,3 +14,11 @@ DO $$
|
|
|
14
14
|
WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.sticky_host_id already exists';
|
|
15
15
|
END;
|
|
16
16
|
$$;
|
|
17
|
+
|
|
18
|
+
DO $$
|
|
19
|
+
BEGIN
|
|
20
|
+
ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN is_greedy BOOLEAN NOT NULL DEFAULT FALSE;
|
|
21
|
+
EXCEPTION
|
|
22
|
+
WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.is_greedy already exists';
|
|
23
|
+
END;
|
|
24
|
+
$$;
|
data/lib/postjob/queue.rb
CHANGED
|
@@ -43,17 +43,23 @@ module Postjob::Queue
|
|
|
43
43
|
tags: [Hash, nil],
|
|
44
44
|
timeout: [Numeric, nil],
|
|
45
45
|
max_attempts: [Integer, nil],
|
|
46
|
-
sticky: [true, false, nil]
|
|
46
|
+
sticky: [true, false, nil],
|
|
47
|
+
greedy: [true, false, nil]
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
workflow, workflow_method = parse_workflow(workflow)
|
|
50
51
|
|
|
52
|
+
if options[:greedy] && !options[:sticky]
|
|
53
|
+
raise ArgumentError, "#{workflow}: A greedy job must also be sticky" unless options[:sticky].nil?
|
|
54
|
+
options[:sticky] = true if options[:greedy]
|
|
55
|
+
end
|
|
56
|
+
|
|
51
57
|
# The use of a `SELECT * FROM function()` here is due to
|
|
52
58
|
#
|
|
53
59
|
# a) a limitation in Simple::SQL which would not be able to unpack a
|
|
54
60
|
# "SELECT function()" usefully when the return value is a record;
|
|
55
61
|
# b) and/or my inability to write better SQL functions;
|
|
56
|
-
SQL.ask "SELECT * FROM #{SCHEMA_NAME}.enqueue($1::uuid, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
|
62
|
+
SQL.ask "SELECT * FROM #{SCHEMA_NAME}.enqueue($1::uuid, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
|
|
57
63
|
worker_session_id,
|
|
58
64
|
options[:queue],
|
|
59
65
|
workflow,
|
|
@@ -66,6 +72,7 @@ module Postjob::Queue
|
|
|
66
72
|
options[:timeout],
|
|
67
73
|
options[:cron_interval],
|
|
68
74
|
options[:sticky],
|
|
75
|
+
options[:greedy],
|
|
69
76
|
into: Job
|
|
70
77
|
end
|
|
71
78
|
|
|
@@ -162,7 +169,6 @@ module Postjob::Queue
|
|
|
162
169
|
expect! queue => [ nil, Array, String ]
|
|
163
170
|
|
|
164
171
|
queue = Array(queue) if queue
|
|
165
|
-
|
|
166
172
|
SQL.ask "SELECT * FROM #{SCHEMA_NAME}.checkout($1::uuid, $2::boolean, $3)",
|
|
167
173
|
worker_session_id, Postjob.fast_mode, queue, into: Job
|
|
168
174
|
end
|
data/lib/postjob/registry.rb
CHANGED
|
@@ -41,6 +41,7 @@ class Postjob::Registry
|
|
|
41
41
|
max_attempts: 5,
|
|
42
42
|
timeout: 15 * 60,
|
|
43
43
|
sticky: false,
|
|
44
|
+
greedy: false,
|
|
44
45
|
cron_interval: nil,
|
|
45
46
|
queue: "ruby"
|
|
46
47
|
}
|
|
@@ -49,6 +50,7 @@ class Postjob::Registry
|
|
|
49
50
|
attr_reader :max_attempts
|
|
50
51
|
attr_reader :timeout
|
|
51
52
|
attr_reader :sticky
|
|
53
|
+
attr_reader :greedy
|
|
52
54
|
attr_reader :cron_interval
|
|
53
55
|
attr_reader :queue
|
|
54
56
|
|
|
@@ -64,10 +66,13 @@ class Postjob::Registry
|
|
|
64
66
|
|
|
65
67
|
options = DEFAULTS.merge(options)
|
|
66
68
|
|
|
69
|
+
options[:sticky] ||= options[:greedy]
|
|
70
|
+
|
|
67
71
|
@version = options[:version]
|
|
68
72
|
@max_attempts = options[:max_attempts]
|
|
69
73
|
@timeout = options[:timeout]
|
|
70
74
|
@sticky = options[:sticky]
|
|
75
|
+
@greedy = options[:greedy]
|
|
71
76
|
@cron_interval = options[:cron_interval]
|
|
72
77
|
@queue = options[:queue]
|
|
73
78
|
end
|
|
@@ -78,6 +83,7 @@ class Postjob::Registry
|
|
|
78
83
|
r[:max_attempts] = @max_attempts
|
|
79
84
|
r[:timeout] = @timeout
|
|
80
85
|
r[:sticky] = @sticky
|
|
86
|
+
r[:greedy] = @greedy
|
|
81
87
|
r[:cron_interval] = @cron_interval
|
|
82
88
|
r[:queue] = @queue
|
|
83
89
|
|
|
@@ -109,6 +115,22 @@ class Postjob::Registry
|
|
|
109
115
|
@workflow = workflow
|
|
110
116
|
@options = Options.new(options)
|
|
111
117
|
end
|
|
118
|
+
|
|
119
|
+
def supports_cleanup?
|
|
120
|
+
return false unless lookup_workflow_method(:run)
|
|
121
|
+
return false unless lookup_workflow_method(:cleanup)
|
|
122
|
+
|
|
123
|
+
true
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
def lookup_workflow_method(name)
|
|
129
|
+
return unless workflow.is_a?(Module)
|
|
130
|
+
workflow.method(name)
|
|
131
|
+
rescue NameError
|
|
132
|
+
nil
|
|
133
|
+
end
|
|
112
134
|
end
|
|
113
135
|
|
|
114
136
|
# looks up a specific version of a specific workflow. Returns a WorkflowSpec
|
|
@@ -132,6 +154,10 @@ class Postjob::Registry
|
|
|
132
154
|
end
|
|
133
155
|
|
|
134
156
|
def register(workflow, options)
|
|
157
|
+
if options[:greedy] && options[:sticky] == false
|
|
158
|
+
raise ArgumentError, "#{workflow}: a greedy job must also be sticky"
|
|
159
|
+
end
|
|
160
|
+
|
|
135
161
|
spec = WorkflowSpec.new(workflow, options)
|
|
136
162
|
|
|
137
163
|
@workflows_with_versions << spec.name << "#{spec.name}#{spec.options.version}"
|
data/lib/postjob/runner.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# rubocop:disable Style/BlockDelimiters
|
|
3
3
|
# rubocop:disable Lint/RescueException
|
|
4
4
|
# rubocop:disable Metrics/MethodLength
|
|
5
|
+
# rubocop:disable Metrics/AbcSize
|
|
5
6
|
|
|
6
7
|
# Base implementations for Runners
|
|
7
8
|
#
|
|
@@ -155,6 +156,10 @@ module Postjob::Runner
|
|
|
155
156
|
return_exception :failed, $!
|
|
156
157
|
rescue Postjob::Error::Nonrecoverable
|
|
157
158
|
return_exception :failed, $!
|
|
159
|
+
rescue PG::Error
|
|
160
|
+
Postjob.logger.error "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
|
|
161
|
+
STDERR.puts "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
|
|
162
|
+
return_exception :failed, $!
|
|
158
163
|
rescue Exception
|
|
159
164
|
return_exception :err, $!
|
|
160
165
|
end
|
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(3)
|
|
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")
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: postjob
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- radiospiel
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-08-
|
|
11
|
+
date: 2018-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|