postjob 0.4.2 → 0.4.3
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/ps.rb +15 -8
- data/lib/postjob/cli/run.rb +1 -3
- data/lib/postjob/error.rb +21 -6
- data/lib/postjob/migrations/003b_processing_columns.sql +4 -4
- data/lib/postjob/migrations/006_enqueue.sql +5 -0
- data/lib/postjob/migrations/010_settings.sql +11 -2
- data/lib/postjob/migrations.rb +2 -1
- data/lib/postjob/queue/encoder.rb +8 -2
- data/lib/postjob/queue.rb +8 -1
- data/lib/postjob/runner.rb +13 -3
- data/lib/postjob.rb +11 -0
- data/spec/postjob/job_control/manual_spec.rb +7 -3
- data/spec/postjob/queue/encoder_spec.rb +21 -8
- 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: 0be2321073faba782e89878c47c6c6770b97e7ff
|
4
|
+
data.tar.gz: c9d3cf35e02a4105587d5888535e4297d4abb9af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 208afca0daf608d1ada39ad4fac5539e2ad10388d73e469bc4164eee2f49c4615a0e845578dd1aad5db6fe33f0decdef62c0329b198fa4f44f2e9941363eb2e7
|
7
|
+
data.tar.gz: 11a854fb585336169a6b218884d8b02503c5e52503efac95609b937dc18dd51703868f93a569f3fb66b557c411215bf9ecf797f5ddd33a4781a750092676855f
|
data/lib/postjob/cli/ps.rb
CHANGED
@@ -18,20 +18,27 @@ module Postjob::CLI
|
|
18
18
|
|| workflow_version
|
19
19
|
|| (CASE WHEN workflow_method != 'run' THEN '.' || workflow_method ELSE '' END)
|
20
20
|
|| args AS job,
|
21
|
-
|
22
|
-
|
21
|
+
CASE
|
22
|
+
WHEN (status = 'err') THEN 'err(' || failed_attempts || '/' || max_attempts || ')'
|
23
|
+
ELSE status::varchar
|
24
|
+
END AS status,
|
23
25
|
error,
|
24
26
|
COALESCE((results->0)::varchar, error_message) AS result,
|
25
27
|
next_run_at,
|
26
28
|
next_run_at - (now() at time zone 'utc') AS next_run_in,
|
27
29
|
to_char(EXTRACT(EPOCH FROM (now() at time zone 'utc') - postjobs.created_at), '999999999.99') AS age,
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
|
31
|
+
CASE
|
32
|
+
WHEN processing_started_at IS NOT NULL THEN
|
33
|
+
format(
|
34
|
+
'%s/%s',
|
35
|
+
to_char(EXTRACT(EPOCH FROM (now() at time zone 'utc') - processing_started_at), '999999999.99'),
|
36
|
+
processing_max_duration
|
37
|
+
)
|
38
|
+
WHEN status IN ('failed', 'err', 'ok') THEN
|
39
|
+
format('%s', to_char(EXTRACT(EPOCH FROM (updated_at - created_at)), '999999999.99'))
|
34
40
|
END AS processing,
|
41
|
+
|
35
42
|
COALESCE(processing_client, '') || COALESCE('/' || processing_client_identifier, '') AS worker,
|
36
43
|
tags
|
37
44
|
FROM postjob.postjobs AS postjobs
|
data/lib/postjob/cli/run.rb
CHANGED
@@ -11,12 +11,10 @@ module Postjob::CLI
|
|
11
11
|
# Parameters:
|
12
12
|
#
|
13
13
|
# - count=<count> maximum number of jobs to process. Default: unlimited.
|
14
|
-
# - fast=<count> reduce waiting time after error (for development only!)
|
15
14
|
# - quiet don't show progress.
|
16
15
|
#
|
17
|
-
def run(count: nil,
|
16
|
+
def run(count: nil, quiet: false)
|
18
17
|
count = Integer(count) if count
|
19
|
-
Postjob.fast_mode = fast
|
20
18
|
|
21
19
|
connect_to_database!
|
22
20
|
|
data/lib/postjob/error.rb
CHANGED
@@ -1,16 +1,31 @@
|
|
1
1
|
module Postjob
|
2
2
|
class Error < RuntimeError
|
3
|
-
|
4
|
-
|
3
|
+
attr_reader :message
|
4
|
+
|
5
|
+
def initialize(err)
|
6
|
+
case err
|
7
|
+
when ::Postjob::Job then @message = job_error_msg(err)
|
8
|
+
when nil, false then @message = self.class.name
|
9
|
+
else @message = err.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
message
|
5
15
|
end
|
6
16
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
17
|
+
private
|
18
|
+
|
19
|
+
def job_error_msg(job)
|
20
|
+
error_msg = "Failing child job"
|
21
|
+
error_msg += " [#{job.result}]" if job.result
|
22
|
+
error_msg
|
11
23
|
end
|
12
24
|
end
|
13
25
|
|
14
26
|
class Error::Nonrecoverable < Error
|
15
27
|
end
|
28
|
+
|
29
|
+
class Error::Encoding < Error::Nonrecoverable
|
30
|
+
end
|
16
31
|
end
|
@@ -2,7 +2,7 @@ DO $$
|
|
2
2
|
BEGIN
|
3
3
|
ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_client varchar;
|
4
4
|
EXCEPTION
|
5
|
-
WHEN duplicate_column THEN RAISE
|
5
|
+
WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_client already exists';
|
6
6
|
END;
|
7
7
|
$$;
|
8
8
|
|
@@ -10,7 +10,7 @@ DO $$
|
|
10
10
|
BEGIN
|
11
11
|
ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_client_identifier varchar;
|
12
12
|
EXCEPTION
|
13
|
-
WHEN duplicate_column THEN RAISE
|
13
|
+
WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_client_identifier already exists';
|
14
14
|
END;
|
15
15
|
$$;
|
16
16
|
|
@@ -18,7 +18,7 @@ DO $$
|
|
18
18
|
BEGIN
|
19
19
|
ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_started_at timestamp;
|
20
20
|
EXCEPTION
|
21
|
-
WHEN duplicate_column THEN RAISE
|
21
|
+
WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_started_at already exists';
|
22
22
|
END;
|
23
23
|
$$;
|
24
24
|
|
@@ -26,6 +26,6 @@ DO $$
|
|
26
26
|
BEGIN
|
27
27
|
ALTER TABLE {SCHEMA_NAME}.postjobs ADD COLUMN processing_max_duration float;
|
28
28
|
EXCEPTION
|
29
|
-
WHEN duplicate_column THEN RAISE
|
29
|
+
WHEN duplicate_column THEN RAISE DEBUG 'column {SCHEMA_NAME}.postjobs.processing_max_duration already exists';
|
30
30
|
END;
|
31
31
|
$$;
|
@@ -14,6 +14,11 @@ AS $$
|
|
14
14
|
job_id BIGINT;
|
15
15
|
BEGIN
|
16
16
|
-- set defaults ---------------------------------------------------
|
17
|
+
IF workflow = '__manual__' AND COALESCE(max_attempts, 1) != 1 THEN
|
18
|
+
RAISE NOTICE 'Adjusting max_attempts of __manual__ job to 1';
|
19
|
+
max_attempts := 1;
|
20
|
+
END IF;
|
21
|
+
|
17
22
|
workflow_version := COALESCE(workflow_version, '');
|
18
23
|
queue := COALESCE(queue, 'q');
|
19
24
|
max_attempts := COALESCE(max_attempts, 5);
|
@@ -3,5 +3,14 @@ CREATE TABLE IF NOT EXISTS {SCHEMA_NAME}.settings (
|
|
3
3
|
value VARCHAR
|
4
4
|
);
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
CREATE OR REPLACE FUNCTION {SCHEMA_NAME}.update_settings(p_name VARCHAR, p_value VARCHAR)
|
7
|
+
RETURNS VOID
|
8
|
+
AS $$
|
9
|
+
BEGIN
|
10
|
+
INSERT INTO {SCHEMA_NAME}.settings (name, value) VALUES(p_name, p_value)
|
11
|
+
ON CONFLICT(name) DO UPDATE SET value = p_value;
|
12
|
+
END;
|
13
|
+
$$ LANGUAGE plpgsql;
|
14
|
+
|
15
|
+
SELECT {SCHEMA_NAME}.update_settings('version', '0.4.2');
|
16
|
+
SELECT {SCHEMA_NAME}.update_settings('client_version', '{CLIENT_VERSION}');
|
data/lib/postjob/migrations.rb
CHANGED
@@ -16,6 +16,7 @@ module Postjob
|
|
16
16
|
expect! SCHEMA_NAME != "public"
|
17
17
|
|
18
18
|
def unmigrate!
|
19
|
+
SQL.exec "SET client_min_messages TO WARNING"
|
19
20
|
SQL.exec "DROP SCHEMA IF EXISTS #{SCHEMA_NAME} CASCADE"
|
20
21
|
end
|
21
22
|
|
@@ -30,7 +31,7 @@ module Postjob
|
|
30
31
|
private
|
31
32
|
|
32
33
|
def run_migration(file)
|
33
|
-
|
34
|
+
Postjob.logger.debug "[postjob] Running migration in #{file}"
|
34
35
|
|
35
36
|
case file
|
36
37
|
when /\.rb$/ then run_migration_ruby(file)
|
@@ -16,11 +16,17 @@ require "json"
|
|
16
16
|
module Postjob::Queue::Encoder
|
17
17
|
extend self
|
18
18
|
|
19
|
+
def check_encodable!(data)
|
20
|
+
encode(data)
|
21
|
+
end
|
22
|
+
|
19
23
|
def encode(data)
|
20
24
|
return nil if data.nil?
|
21
25
|
|
22
26
|
verify_encodable!(data)
|
23
|
-
JSON.generate(data)
|
27
|
+
::JSON.generate(data)
|
28
|
+
rescue ::JSON::JSONError, ::EncodingError
|
29
|
+
raise ::Postjob::Error::Encoding, $!.to_s
|
24
30
|
end
|
25
31
|
|
26
32
|
private
|
@@ -35,7 +41,7 @@ module Postjob::Queue::Encoder
|
|
35
41
|
when Array then obj.each { |entry| verify_encodable!(entry) }
|
36
42
|
else
|
37
43
|
msg = "Unencodable #{obj.class.name} object: #{obj.inspect}"
|
38
|
-
raise
|
44
|
+
raise ::Postjob::Error::Encoding, msg
|
39
45
|
end
|
40
46
|
end
|
41
47
|
end
|
data/lib/postjob/queue.rb
CHANGED
@@ -89,7 +89,14 @@ module Postjob::Queue
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def find_or_create_childjob(parent, workflow, args, timeout:, max_attempts:, queue: nil)
|
92
|
-
expect! parent => Job
|
92
|
+
expect! parent => Job
|
93
|
+
expect! workflow => String
|
94
|
+
expect! args => Array
|
95
|
+
|
96
|
+
if workflow == "__manual__" && max_attempts != 1
|
97
|
+
Postjob.logger.info "Job ##{parent.id} adjusting max_attempts of '__manual__' child job"
|
98
|
+
max_attempts = 1
|
99
|
+
end
|
93
100
|
|
94
101
|
workflow, workflow_method = parse_workflow(workflow)
|
95
102
|
|
data/lib/postjob/runner.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# rubocop:disable Metrics/ModuleLength
|
2
2
|
# rubocop:disable Style/BlockDelimiters
|
3
3
|
# rubocop:disable Lint/RescueException
|
4
|
+
# rubocop:disable Metrics/MethodLength
|
4
5
|
|
5
6
|
module Postjob::Runner
|
6
7
|
extend self
|
@@ -119,13 +120,22 @@ module Postjob::Runner
|
|
119
120
|
workflow.public_send workflow_method, *args
|
120
121
|
}
|
121
122
|
|
122
|
-
|
123
|
-
|
124
|
-
else
|
123
|
+
if value == :pending
|
124
|
+
[ :pending, nil, nil ]
|
125
|
+
else
|
126
|
+
# Check that we can encode the value. If we can't the job returned something invalid
|
127
|
+
# i.e. something we cannot encode as JSON. This will raise a Postjob::Queue::Encoder::Error.
|
128
|
+
#
|
129
|
+
# Usually this points to a non-UTF8 string.
|
130
|
+
# This is a fix for https://github.com/mediapeers/postjob/issues/35
|
131
|
+
Postjob::Queue::Encoder.check_encodable!([value])
|
132
|
+
[ :ok, value, nil ]
|
125
133
|
end
|
126
134
|
rescue ArgumentError, LocalJumpError, NameError, RegexpError, ScriptError, TypeError
|
127
135
|
Postjob.logger.error "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
|
128
136
|
return_exception :failed, $!
|
137
|
+
rescue Postjob::Error::Nonrecoverable
|
138
|
+
return_exception :failed, $!
|
129
139
|
rescue Exception
|
130
140
|
return_exception :err, $!
|
131
141
|
end
|
data/lib/postjob.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# rubocop:disable Metrics/ParameterLists
|
2
|
+
# rubocop:disable Metrics/MethodLength
|
2
3
|
|
3
4
|
require "expectation"
|
4
5
|
require "simple/sql"
|
@@ -40,6 +41,16 @@ module Postjob
|
|
40
41
|
expect! timeout => [nil, Numeric]
|
41
42
|
expect! tags => [nil, Hash]
|
42
43
|
|
44
|
+
if workflow == "__manual__" && max_attempts != 1
|
45
|
+
if parent_id
|
46
|
+
Postjob.logger.info "Job ##{parent_id} adjusting max_attempts of '__manual__' child job"
|
47
|
+
else
|
48
|
+
Postjob.logger.info "Adjusting max_attempts of '__manual__' root job"
|
49
|
+
end
|
50
|
+
|
51
|
+
max_attempts = 1
|
52
|
+
end
|
53
|
+
|
43
54
|
tags = stringify_hash(tags) if tags
|
44
55
|
job = Queue.enqueue_job workflow, *args, queue: queue,
|
45
56
|
parent_id: parent_id,
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
module ManualWorkflow
|
4
|
-
def self.run
|
5
|
-
job = async :manual, timeout: 10
|
4
|
+
def self.run(max_attempts)
|
5
|
+
job = async :manual, timeout: 10, max_attempts: max_attempts
|
6
6
|
_token = workflow_token job
|
7
7
|
manual_result = await job
|
8
8
|
"manual-result:#{manual_result}"
|
@@ -12,7 +12,7 @@ module ManualWorkflow
|
|
12
12
|
end
|
13
13
|
|
14
14
|
describe "manual processing" do
|
15
|
-
let!(:id) { Postjob.enqueue! "ManualWorkflow" }
|
15
|
+
let!(:id) { Postjob.enqueue! "ManualWorkflow", 3 }
|
16
16
|
|
17
17
|
include TestHelper
|
18
18
|
|
@@ -24,6 +24,10 @@ describe "manual processing" do
|
|
24
24
|
TestHelper.load_job "SELECT * FROM postjobs WHERE parent_id=$1", id
|
25
25
|
end
|
26
26
|
|
27
|
+
it "sets max_attempts to 1" do
|
28
|
+
expect(load_child_job[:max_attempts]).to eq(1)
|
29
|
+
end
|
30
|
+
|
27
31
|
it "creates a UUID token" do
|
28
32
|
token = load_token(load_child_job)
|
29
33
|
expect! token => /[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[a-fA-F0-9]{4}-[A-F0-9]{12}/i
|
@@ -37,14 +37,27 @@ describe "Postjob::Queue::Encoder" do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
describe "invalid input" do
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
def self.check_value(value)
|
41
|
+
it "cannot encode input" do
|
42
|
+
expect do
|
43
|
+
run_workflow input: value
|
44
|
+
end.to raise_error(::Postjob::Error::Encoding)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "cannot encode output" do
|
48
|
+
expect do
|
49
|
+
run_workflow output: value
|
50
|
+
end.to raise_error(::Postjob::Error::Encoding)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when encoding symbols" do
|
55
|
+
check_value :foo
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when encoding invalid utf8 strings" do
|
59
|
+
check_value 255.chr.force_encoding("utf-8")
|
60
|
+
check_value 255.chr
|
48
61
|
end
|
49
62
|
end
|
50
63
|
end
|
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.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|