postjob 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/postjob/cli/version.rb +8 -4
- data/lib/postjob/job.rb +1 -1
- data/lib/postjob/queue/database_info.rb +23 -0
- data/lib/postjob/queue/search.rb +100 -62
- data/lib/postjob/worker_session.rb +2 -2
- data/spec/postjob/queue/search_spec.rb +11 -11
- data/spec/spec_helper.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4fcc6c18ad2be617abafbdfb1dc6258a435223a0fbd0110d86806b6da47fc5d6
|
4
|
+
data.tar.gz: 98a5384f074100eb291d6357993969fea6da7b058177ba513f79329bc558d9c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 212977ecccd8f11df6d0e4950155cc47f18c1d6c979b045109b5f981d5eb1e7a68c90aefae78708385458d102870f3d3c9357d8861fa9a54fd5f58c8db9f4f2b
|
7
|
+
data.tar.gz: c31025b4869355c9dd13ed5e119c43133b9ae794eecaa2c12f92eb07c1e476f48c32cefa182757358b7236b64febe34283183d5f492a71116e86569adb36e724
|
data/lib/postjob/cli/version.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
module Postjob::CLI
|
2
2
|
# Prints version info
|
3
3
|
def version
|
4
|
-
connect_to_database!
|
5
|
-
|
6
4
|
gem_version = Gem.loaded_specs["postjob"].version
|
7
|
-
puts "postjob
|
8
|
-
|
5
|
+
puts "This is postjob (ruby) #{gem_version}"
|
6
|
+
|
7
|
+
begin
|
8
|
+
connect_to_database!
|
9
|
+
puts "postjob/queue: #{::Postjob::Queue.version}"
|
10
|
+
rescue StandardError
|
11
|
+
Postjob.logger.warn "Cannot read postjob schema version. Database might not be configured or migrated."
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
data/lib/postjob/job.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
# This module holds cached database info, to be used by the search functions.
|
2
|
+
module Postjob::Queue::DatabaseInfo
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# returns a Hash of column_name => column_type. Names are available both as
|
6
|
+
# Symbol and as String.
|
7
|
+
def column_types(table_name)
|
8
|
+
@column_types ||= {}
|
9
|
+
@column_types[table_name] ||= begin
|
10
|
+
column_info = ::Simple::SQL::Reflection.column_info(table_name)
|
11
|
+
hsh = {}
|
12
|
+
column_info.each do |column, rec|
|
13
|
+
hsh[column.to_sym] = hsh[column.to_s] = rec.data_type
|
14
|
+
end
|
15
|
+
hsh
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def table_columns(table_name)
|
20
|
+
@table_columns ||= {}
|
21
|
+
@table_columns[table_name] ||= Simple::SQL::Reflection.columns(table_name)
|
22
|
+
end
|
23
|
+
end
|
data/lib/postjob/queue/search.rb
CHANGED
@@ -1,82 +1,120 @@
|
|
1
|
+
require_relative "./database_info"
|
2
|
+
|
1
3
|
module Postjob::Queue
|
2
|
-
|
3
|
-
|
4
|
-
"COALESCE((results->0)::varchar, error_message) AS result",
|
5
|
-
"(now() at time zone 'utc') - created_at AS age",
|
6
|
-
"updated_at - created_at AS runtime"
|
7
|
-
]
|
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
|
4
|
+
class ScopeBuilder
|
5
|
+
SCHEMA_NAME = ::Postjob::Queue::SCHEMA_NAME
|
15
6
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
expect! filter => Hash
|
21
|
-
|
22
|
-
# extract options
|
23
|
-
filter = filter.dup
|
24
|
-
root_only = filter.delete(:root_only) || false
|
25
|
-
attributes = filter.delete(:attributes) || default_attributes
|
26
|
-
expect! attributes => Array
|
27
|
-
|
28
|
-
# build Scope
|
29
|
-
scope = Simple::SQL::Scope.new("SELECT #{attributes.join(", ")} FROM #{SCHEMA_NAME}.postjobs")
|
30
|
-
scope = scope.where("root_id=id") if root_only
|
31
|
-
scope = apply_filters(scope, filter) if filter && !filter.empty?
|
32
|
-
scope
|
33
|
-
end
|
7
|
+
class << self
|
8
|
+
def build(model:, filter:, attributes:)
|
9
|
+
builder(model).send(:scope, filter: filter, attributes: attributes)
|
10
|
+
end
|
34
11
|
|
35
|
-
|
12
|
+
private
|
36
13
|
|
37
|
-
|
38
|
-
|
39
|
-
|
14
|
+
# Returns the name of the column used for dynamic filtering.
|
15
|
+
def dynamic_filter(model)
|
16
|
+
case model
|
17
|
+
when "postjobs" then "tags"
|
18
|
+
else "attributes"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def builder(model)
|
23
|
+
@builders ||= {}
|
24
|
+
@builders[model] ||= new(model: model, dynamic_filter: dynamic_filter(model))
|
25
|
+
end
|
40
26
|
end
|
41
27
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
28
|
+
private
|
29
|
+
|
30
|
+
def initialize(model:, dynamic_filter:)
|
31
|
+
@model = model
|
32
|
+
@table_name = "#{SCHEMA_NAME}.#{model}"
|
33
|
+
@column_types = ::Postjob::Queue::DatabaseInfo.column_types(@table_name)
|
34
|
+
@dynamic_filter = dynamic_filter
|
46
35
|
end
|
47
36
|
|
48
|
-
|
37
|
+
def scope(filter:, attributes:)
|
38
|
+
expect! filter => [Hash, nil]
|
39
|
+
expect! attributes => Array
|
49
40
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
# build Scope
|
42
|
+
scope = Simple::SQL::Scope.new("SELECT #{attributes.join(", ")} FROM #{@table_name}")
|
43
|
+
scope = apply_filters(scope, filter) if filter && !filter.empty?
|
44
|
+
scope
|
45
|
+
end
|
46
|
+
|
47
|
+
# apply the filter hash onto the passed in scope. This matches all filters
|
48
|
+
# with a name which is matching a column name against the column values.
|
49
|
+
# It matches every other filter value against an entry in the
|
50
|
+
# dynamic_filter column.
|
51
|
+
def apply_filters(scope, filter)
|
52
|
+
filter.each_key do |key|
|
53
|
+
expect! key => [Symbol, String]
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
converted_filters = filter.inject({}) do |hsh, (key, value)|
|
57
|
+
matches = convert_filter_value(value, key: key)
|
58
|
+
matches = matches.first if matches.length == 1
|
59
|
+
hsh.update key => matches
|
60
|
+
end
|
61
|
+
|
62
|
+
column_filters, tags_filters = converted_filters.partition { |key, _| !@column_types[key].nil? }
|
63
|
+
|
64
|
+
scope = scope.where(Hash[column_filters]) unless column_filters.empty?
|
65
|
+
scope = scope.where(@dynamic_filter => Hash[tags_filters]) unless tags_filters.empty?
|
66
|
+
|
67
|
+
scope
|
58
68
|
end
|
59
69
|
|
60
|
-
|
70
|
+
def convert_filter_value(value, key:)
|
71
|
+
value = Array(value)
|
61
72
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
73
|
+
case @column_types[key]
|
74
|
+
when "bigint" then value.map { |v| Integer(v) }
|
75
|
+
when "integer" then value.map { |v| Integer(v) }
|
76
|
+
when nil then value.map(&:to_s) + value.grep(/\A-?\d+\z/).map(&:to_i)
|
77
|
+
else value.map(&:to_s)
|
67
78
|
end
|
68
|
-
hsh
|
69
79
|
end
|
70
80
|
end
|
71
81
|
|
72
|
-
|
73
|
-
|
82
|
+
# Builds a search scope (see Simple::SQL::Scope) for the passed in filter criteria.
|
83
|
+
#
|
84
|
+
# Parameters:
|
85
|
+
#
|
86
|
+
# - model: the name of the postjob model, e.g. "postjobs", "events", ..
|
87
|
+
# - filter: a Hash of filter values and other options. options are denoted
|
88
|
+
# by a Symbol key.
|
89
|
+
#
|
90
|
+
# Note that the search scope is unsorted.
|
91
|
+
def search(model, filter = {})
|
92
|
+
expect! model => String
|
93
|
+
expect! filter => [Hash, nil]
|
74
94
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
95
|
+
filter = filter ? filter.dup : {}
|
96
|
+
|
97
|
+
root_only = filter.delete(:root_only)
|
98
|
+
attributes = filter.delete(:attributes) || default_search_attributes(model)
|
99
|
+
|
100
|
+
scope = ScopeBuilder.build(model: model, filter: filter, attributes: attributes)
|
101
|
+
scope = scope.where("root_id=id") if root_only && model == "postjobs"
|
102
|
+
scope
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# describes which attributes should be returned in addition to a model's columns.
|
108
|
+
EXTRA_SEARCH_ATTRIBUTES = {
|
109
|
+
"postjobs" => [
|
110
|
+
"workflow || COALESCE('@' || workflow_version, '') || args AS job",
|
111
|
+
"COALESCE((results->0)::varchar, error_message) AS result",
|
112
|
+
"(now() at time zone 'utc') - created_at AS age",
|
113
|
+
"updated_at - created_at AS runtime"
|
114
|
+
]
|
115
|
+
}
|
116
|
+
|
117
|
+
def default_search_attributes(model)
|
118
|
+
DatabaseInfo.table_columns("#{SCHEMA_NAME}.#{model}") + (EXTRA_SEARCH_ATTRIBUTES[model] || [])
|
81
119
|
end
|
82
120
|
end
|
@@ -14,14 +14,14 @@ end
|
|
14
14
|
|
15
15
|
# A worker worker_session
|
16
16
|
class Postjob::WorkerSession < Postjob::Record
|
17
|
-
|
17
|
+
HOST_ID_PATH = ".postjob.host_id"
|
18
18
|
|
19
19
|
class << self
|
20
20
|
# Starts a worker session.
|
21
21
|
def start!(workflows_with_versions)
|
22
22
|
worker_session = nil
|
23
23
|
|
24
|
-
AtomicStore.with(
|
24
|
+
AtomicStore.with(HOST_ID_PATH) do |host_id|
|
25
25
|
host_id ||= ::Postjob::Host.register
|
26
26
|
Postjob.logger.debug "Starting worker_session w/host_id #{host_id.inspect}"
|
27
27
|
worker_session = ::Postjob::Queue.start_worker_session(workflows_with_versions, host_id: host_id)
|
@@ -27,7 +27,7 @@ describe "Postjob::Queue.search" do
|
|
27
27
|
|
28
28
|
context "attributes" do
|
29
29
|
it "returns a specific set of attributes" do
|
30
|
-
scope = Postjob::Queue.search(id: id)
|
30
|
+
scope = Postjob::Queue.search("postjobs", id: id)
|
31
31
|
result = Simple::SQL.ask scope, into: Hash
|
32
32
|
|
33
33
|
expected_keys = [
|
@@ -47,7 +47,7 @@ describe "Postjob::Queue.search" do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it "with attributes: argument it only returns the specified attributes" do
|
50
|
-
scope = Postjob::Queue.search(attributes: %w(id))
|
50
|
+
scope = Postjob::Queue.search("postjobs", attributes: %w(id))
|
51
51
|
result = Simple::SQL.ask scope, into: Hash
|
52
52
|
|
53
53
|
expected_keys = [
|
@@ -64,7 +64,7 @@ describe "Postjob::Queue.search" do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
it "returns all entries" do
|
67
|
-
scope = Postjob::Queue.search
|
67
|
+
scope = Postjob::Queue.search("postjobs")
|
68
68
|
result = Simple::SQL.all(scope, into: OpenStruct)
|
69
69
|
expect(result.length).to eq(2)
|
70
70
|
end
|
@@ -72,46 +72,46 @@ describe "Postjob::Queue.search" do
|
|
72
72
|
|
73
73
|
describe "filtering" do
|
74
74
|
it "can find a job by id" do
|
75
|
-
scope = Postjob::Queue.search(id: id)
|
75
|
+
scope = Postjob::Queue.search("postjobs", id: id)
|
76
76
|
result = Simple::SQL.ask scope, into: Hash
|
77
77
|
expect(result[:id]).to eq(id)
|
78
78
|
end
|
79
79
|
|
80
80
|
it "positive filters by tags" do
|
81
|
-
scope = Postjob::Queue.search("initial" => "yay")
|
81
|
+
scope = Postjob::Queue.search("postjobs", "initial" => "yay")
|
82
82
|
result = Simple::SQL.all scope, into: OpenStruct
|
83
83
|
expect(result.length).to eq(1)
|
84
84
|
expect(result.first.id).to eq(id)
|
85
85
|
end
|
86
86
|
|
87
87
|
it "negative filters by tags" do
|
88
|
-
scope = Postjob::Queue.search("initial" => "nay")
|
88
|
+
scope = Postjob::Queue.search("postjobs", "initial" => "nay")
|
89
89
|
result = Simple::SQL.all(scope)
|
90
90
|
expect(result.length).to eq(0)
|
91
91
|
end
|
92
92
|
|
93
93
|
it "filter tags against empty array" do
|
94
|
-
scope = Postjob::Queue.search("initial" => [])
|
94
|
+
scope = Postjob::Queue.search("postjobs", "initial" => [])
|
95
95
|
result = Simple::SQL.all(scope)
|
96
96
|
expect(result.length).to eq(0)
|
97
97
|
end
|
98
98
|
|
99
99
|
it "filter tags against multiple matches" do
|
100
|
-
scope = Postjob::Queue.search("initial" => [ "yay", "nay" ])
|
100
|
+
scope = Postjob::Queue.search("postjobs", "initial" => [ "yay", "nay" ])
|
101
101
|
result = Simple::SQL.all(scope)
|
102
102
|
expect(result.length).to eq(1)
|
103
103
|
end
|
104
104
|
|
105
105
|
it "filter tags against a combination of multiple matches" do
|
106
|
-
scope = Postjob::Queue.search("initial" => [ "yay", "nay" ], "multi" => "manyay")
|
106
|
+
scope = Postjob::Queue.search("postjobs", "initial" => [ "yay", "nay" ], "multi" => "manyay")
|
107
107
|
result = Simple::SQL.all(scope)
|
108
108
|
expect(result.length).to eq(1)
|
109
109
|
|
110
|
-
scope = Postjob::Queue.search("initial" => [ "yay", "nay" ], "multi" => "nay")
|
110
|
+
scope = Postjob::Queue.search("postjobs", "initial" => [ "yay", "nay" ], "multi" => "nay")
|
111
111
|
result = Simple::SQL.all(scope)
|
112
112
|
expect(result.length).to eq(0)
|
113
113
|
|
114
|
-
scope = Postjob::Queue.search("initial" => [ "yay", "nay" ], "multi" => ["nay", "manyay"])
|
114
|
+
scope = Postjob::Queue.search("postjobs", "initial" => [ "yay", "nay" ], "multi" => ["nay", "manyay"])
|
115
115
|
result = Simple::SQL.all(scope)
|
116
116
|
expect(result.length).to eq(1)
|
117
117
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
@@ -261,6 +261,7 @@ files:
|
|
261
261
|
- lib/postjob/migrations/018_heartbeat.sql
|
262
262
|
- lib/postjob/migrations/019_heartbeat_indices.sql
|
263
263
|
- lib/postjob/queue.rb
|
264
|
+
- lib/postjob/queue/database_info.rb
|
264
265
|
- lib/postjob/queue/encoder.rb
|
265
266
|
- lib/postjob/queue/notifications.rb
|
266
267
|
- lib/postjob/queue/search.rb
|
@@ -314,7 +315,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
314
315
|
version: '0'
|
315
316
|
requirements: []
|
316
317
|
rubyforge_project:
|
317
|
-
rubygems_version: 2.
|
318
|
+
rubygems_version: 2.7.7
|
318
319
|
signing_key:
|
319
320
|
specification_version: 4
|
320
321
|
summary: restartable, asynchronous, and distributed processes
|