postjob 0.5.1 → 0.5.2
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 +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
|