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