postjob 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/postjob/job.rb +10 -0
- data/lib/postjob/migrations/003_postjobs.sql +44 -15
- data/lib/postjob/migrations/004_tokens.sql +3 -0
- data/lib/postjob/queue/search.rb +43 -15
- data/lib/postjob/runner.rb +7 -0
- data/spec/spec_helper.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78a70bee1c76f0285da58ecc0e1f38f4d420d9f1
|
4
|
+
data.tar.gz: 4fe406b37ebe91e317c00a6c8cb84fceb6b5ce55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e55f152396f288ee5f51ccbc08ab23cb54e82f8afac7b8b69a248d38ff2ada757c075292008810ed749ba585f01591d87cb2780ab49289b46948a83b7360296
|
7
|
+
data.tar.gz: b7ccda0358d5377e8d4bcb089e736fd3f06efe5149f82a6ee792870dcfc05f5966f739313fd53834f501fa9901afdd76473b75be22fd70a780b751cc621a0241
|
data/lib/postjob/job.rb
CHANGED
@@ -9,6 +9,11 @@ class Postjob::Job < Hash
|
|
9
9
|
replace hsh.dup
|
10
10
|
end
|
11
11
|
|
12
|
+
def self.find(job_id)
|
13
|
+
scope = Postjob::Queue.search(id: job_id)
|
14
|
+
Simple::SQL.ask(scope, into: Postjob::Job)
|
15
|
+
end
|
16
|
+
|
12
17
|
def self.attribute(sym)
|
13
18
|
eval <<~RUBY
|
14
19
|
define_method(:#{sym}) { self[:#{sym}] }
|
@@ -55,6 +60,11 @@ class Postjob::Job < Hash
|
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
63
|
+
def resolved?
|
64
|
+
expect! status => STATUSES
|
65
|
+
%w(ok timeout failed).include?(status)
|
66
|
+
end
|
67
|
+
|
58
68
|
def result
|
59
69
|
results && results.first
|
60
70
|
end
|
@@ -1,37 +1,66 @@
|
|
1
1
|
CREATE TABLE IF NOT EXISTS {SCHEMA_NAME}.postjobs (
|
2
|
-
--
|
2
|
+
-- identifiers ------------------------------------------------------------------------------------------
|
3
|
+
-- These are set when enqueueing a workflow
|
3
4
|
id BIGSERIAL PRIMARY KEY, -- process id
|
4
|
-
parent_id BIGINT REFERENCES {SCHEMA_NAME}.postjobs ON DELETE CASCADE,
|
5
|
+
parent_id BIGINT REFERENCES {SCHEMA_NAME}.postjobs ON DELETE CASCADE, -- parent process id
|
5
6
|
full_id VARCHAR, -- full process id
|
6
7
|
root_id BIGINT, -- root process id
|
7
8
|
|
9
|
+
-- timestamps -------------------------------------------------------------------------------------------
|
10
|
+
-- managed automatically
|
8
11
|
created_at timestamp NOT NULL DEFAULT (now() at time zone 'utc'), -- creation timestamp
|
9
12
|
updated_at timestamp NOT NULL DEFAULT (now() at time zone 'utc'), -- update timestamp
|
10
13
|
|
14
|
+
-- workflow specification -------------------------------------------------------------------------------
|
15
|
+
-- Set when enqueueing the workflow, readonly
|
16
|
+
|
11
17
|
queue VARCHAR, -- queue name. (readonly)
|
12
18
|
workflow VARCHAR NOT NULL, -- e.g. "MyJobModule" (readonly)
|
13
19
|
workflow_method VARCHAR NOT NULL DEFAULT 'run', -- e.g. "run" (readonly)
|
14
|
-
workflow_version VARCHAR NOT NULL DEFAULT '', -- e.g. "1.0"
|
15
20
|
args JSONB, -- args
|
21
|
+
timing_out_at timestamp, -- job times out after this timestamp
|
22
|
+
max_attempts INTEGER NOT NULL DEFAULT 1, -- maximum attempts before failing
|
23
|
+
|
24
|
+
-- process state ----------------------------------------------------------------------------------------
|
25
|
+
-- Managed automatically.
|
16
26
|
|
17
|
-
--
|
27
|
+
-- The workflow version is pinned as soon as the workflow is running for the first time.
|
28
|
+
-- It is readonly afterwards. Note that the default is not NULL, but '', because this allows
|
29
|
+
-- to query via (workflow, workflow_version) IN (('Foo', ''), ('Foo', '1.0'))
|
30
|
+
workflow_version VARCHAR NOT NULL DEFAULT '', -- e.g. "1.0"
|
18
31
|
|
32
|
+
-- The workflow status, one of 'ready', 'sleep', 'failed', 'err', 'timeout', 'ok'
|
19
33
|
status {SCHEMA_NAME}.statuses DEFAULT 'ready',
|
20
|
-
next_run_at timestamp DEFAULT (now() at time zone 'utc'), -- when possible to run next?
|
21
|
-
timing_out_at timestamp, -- job times out after this timestamp
|
22
|
-
failed_attempts INTEGER NOT NULL DEFAULT 0, -- failed how often?
|
23
|
-
max_attempts INTEGER NOT NULL DEFAULT 1, -- maximum attempts before failing
|
24
34
|
|
25
|
-
--
|
35
|
+
-- Timestamp when consider running this the next time.
|
36
|
+
next_run_at timestamp DEFAULT (now() at time zone 'utc'),
|
37
|
+
|
38
|
+
-- Number of failed attempts so far.
|
39
|
+
failed_attempts INTEGER NOT NULL DEFAULT 0,
|
26
40
|
|
27
|
-
|
28
|
-
error VARCHAR,
|
29
|
-
error_message VARCHAR,
|
30
|
-
error_backtrace JSONB,
|
41
|
+
-- process result ---------------------------------------------------------------------------------------
|
31
42
|
|
32
|
-
--
|
43
|
+
results JSONB, -- The process result, if any. Only valid when status == 'ok'
|
44
|
+
error VARCHAR, -- The last error; usually set to the klass of the error.
|
45
|
+
error_message VARCHAR, -- The human readable error message, for displaying purposes
|
46
|
+
error_backtrace JSONB, -- additional error information, for debugging purposes
|
47
|
+
|
48
|
+
-- custom fields ----------------------------------------------------------------------------------------
|
33
49
|
workflow_status VARCHAR,
|
34
|
-
tags JSONB
|
50
|
+
tags JSONB,
|
51
|
+
|
52
|
+
-- processing_client information ------------------------------------------------------------------------
|
53
|
+
-- This information is passed along from workers during processing. They are only valid
|
54
|
+
-- when status == 'processing'
|
55
|
+
--
|
56
|
+
-- Initially these columns didn't exist, and have been created via another migration
|
57
|
+
-- (003b_processing_columns.sql). They are listed here for documentation purposes.
|
58
|
+
processing_client varchar, -- host:port of client (taken from pg_stat_activity)
|
59
|
+
processing_client_identifier varchar, -- free text info, set via set_client_identifier()
|
60
|
+
processing_started_at timestamp, -- when did processing start?
|
61
|
+
processing_max_duration float -- maximum expected duration of processing. Afterwards the
|
62
|
+
-- processing is considered failed for unknown reasons, and
|
63
|
+
-- potentially restarted.
|
35
64
|
);
|
36
65
|
|
37
66
|
-- [TODO] check indices
|
@@ -1,3 +1,6 @@
|
|
1
|
+
-- The tokens table contains tokens for externally resolvable workflows. They are considered
|
2
|
+
-- secret, and therefore not part of the main table.
|
3
|
+
|
1
4
|
CREATE TABLE IF NOT EXISTS {SCHEMA_NAME}.tokens (
|
2
5
|
id BIGSERIAL PRIMARY KEY,
|
3
6
|
postjob_id BIGINT REFERENCES {SCHEMA_NAME}.postjobs ON DELETE CASCADE,
|
data/lib/postjob/queue/search.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
module Postjob::Queue
|
2
2
|
DEFAULT_ATTRIBUTES = [
|
3
|
-
"id",
|
4
|
-
"full_id",
|
5
3
|
"workflow || COALESCE('@' || workflow_version, '') || args AS job",
|
6
|
-
"workflow_status",
|
7
|
-
"status",
|
8
|
-
"error",
|
9
4
|
"COALESCE((results->0)::varchar, error_message) AS result",
|
10
|
-
"next_run_at",
|
11
|
-
"error_backtrace",
|
12
5
|
"(now() at time zone 'utc') - created_at AS age",
|
13
|
-
"updated_at - created_at AS runtime"
|
14
|
-
"tags"
|
6
|
+
"updated_at - created_at AS runtime"
|
15
7
|
]
|
16
8
|
|
9
|
+
def default_attributes
|
10
|
+
@default_attributes ||= begin
|
11
|
+
column_names = Simple::SQL::Reflection.columns("#{SCHEMA_NAME}.postjobs")
|
12
|
+
column_names + DEFAULT_ATTRIBUTES
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
17
16
|
# Builds a search scope (see Simple::SQL::Scope) for the passed in filter criteria.
|
18
17
|
def search(filter = {})
|
19
18
|
expect! filter => Hash
|
@@ -21,7 +20,7 @@ module Postjob::Queue
|
|
21
20
|
# extract options
|
22
21
|
filter = filter.dup
|
23
22
|
root_only = filter.delete(:root_only) || false
|
24
|
-
attributes = filter.delete(:attributes) ||
|
23
|
+
attributes = filter.delete(:attributes) || default_attributes
|
25
24
|
expect! attributes => Array
|
26
25
|
|
27
26
|
# build Scope
|
@@ -38,17 +37,46 @@ module Postjob::Queue
|
|
38
37
|
expect! key => [Symbol, String]
|
39
38
|
end
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
converted_filters = filter.inject({}) do |hsh, (key, value)|
|
41
|
+
hsh.update key => convert_filter_value(value, key: key)
|
42
|
+
end
|
43
43
|
|
44
|
-
column_filters, tags_filters =
|
44
|
+
column_filters, tags_filters = converted_filters.partition { |key, _| !column_types[key].nil? }
|
45
45
|
|
46
46
|
scope = scope.where(Hash[column_filters])
|
47
47
|
scope = scope.where(tags: Hash[tags_filters])
|
48
48
|
scope
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
class << self
|
52
|
+
def column_types
|
53
|
+
@column_types ||= _column_types
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def _column_types
|
59
|
+
column_info = ::Simple::SQL::Reflection.column_info("#{SCHEMA_NAME}.postjobs")
|
60
|
+
hsh = {}
|
61
|
+
column_info.each do |column, rec|
|
62
|
+
hsh[column.to_sym] = hsh[column.to_s] = rec.data_type
|
63
|
+
end
|
64
|
+
hsh
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def convert_filter_value(value, key:)
|
69
|
+
value = Array(value)
|
70
|
+
|
71
|
+
case Postjob::Queue.column_types[key]
|
72
|
+
when "bigint" then simplify_array(value.map(&:to_i))
|
73
|
+
when "integer" then simplify_array(value.map(&:to_i))
|
74
|
+
when nil then simplify_array(value.map(&:to_i) + value.map(&:to_s))
|
75
|
+
else simplify_array(value.map(&:to_s))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def simplify_array(ary)
|
80
|
+
ary.length == 1 ? ary.first : ary
|
53
81
|
end
|
54
82
|
end
|
data/lib/postjob/runner.rb
CHANGED
@@ -107,6 +107,13 @@ module Postjob::Runner
|
|
107
107
|
private
|
108
108
|
|
109
109
|
# runs a job. Returns a [ status, value, shutdown ] tuple.
|
110
|
+
#
|
111
|
+
# The shutdown value is used by a worker in run mode (i.e. process
|
112
|
+
# indefinetively) to determine whether or not it should cancel
|
113
|
+
# processing. It is usually nil; but if the worker received a
|
114
|
+
# SIGINT it will be :shutdown instead.
|
115
|
+
#
|
116
|
+
# We are catching SIGINT to allow the job status to be updated.
|
110
117
|
def invoke_workflow(workflow, job)
|
111
118
|
value = catch(:pending) {
|
112
119
|
expect! job.args => [Array, nil]
|
data/spec/spec_helper.rb
CHANGED
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
version: '0.4'
|
124
124
|
- - ">="
|
125
125
|
- !ruby/object:Gem::Version
|
126
|
-
version: 0.4.
|
126
|
+
version: 0.4.8
|
127
127
|
type: :runtime
|
128
128
|
prerelease: false
|
129
129
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -133,7 +133,7 @@ dependencies:
|
|
133
133
|
version: '0.4'
|
134
134
|
- - ">="
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version: 0.4.
|
136
|
+
version: 0.4.8
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: simple-cli
|
139
139
|
requirement: !ruby/object:Gem::Requirement
|