postjob 0.1.7 → 0.1.8
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/db.rb +25 -5
- data/lib/postjob/cli/job.rb +3 -3
- data/lib/postjob/cli/ps.rb +3 -3
- data/lib/postjob/queue/encoder.rb +2 -0
- data/lib/postjob/queue/notifications.rb +10 -20
- data/lib/postjob/queue.rb +5 -23
- data/lib/postjob/registry.rb +5 -20
- data/lib/postjob.rb +1 -0
- data/spec/postjob/enqueue_spec.rb +0 -2
- data/spec/postjob/full_workflow_spec.rb +2 -0
- data/spec/postjob/job_control/error_status_spec.rb +73 -0
- data/spec/postjob/job_control/max_attempts_spec.rb +0 -2
- data/spec/postjob/queue/search_spec.rb +0 -2
- data/spec/postjob/run_spec.rb +0 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c750b67a0ab97557768d02f7a3cf2644646a8e1e
|
4
|
+
data.tar.gz: 4b1b93d7c1a261329d92081459c58492cf5a7923
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1310163dededb197a2c53deb03bfc6f0b0e7ec399ab33e870edab619b085fc86633c566b9a0152a07df3c2ef8cae580ebd9f4dccb95435c203794e266946c1d1
|
7
|
+
data.tar.gz: 3e6a73a8f11f8dd828a099ce8b8380e0872a6e23379109d85681d3107937f25d9a992745c48214d0d309b4b37acc681cab5b01620bf30a96f3e3945ae238e769
|
data/lib/postjob/cli/db.rb
CHANGED
@@ -1,28 +1,48 @@
|
|
1
1
|
require "postjob/cli"
|
2
|
+
require "postjob/migrations"
|
2
3
|
|
3
4
|
module Postjob::CLI
|
4
5
|
def db_migrate
|
5
|
-
require "postjob/migrations"
|
6
|
-
|
7
6
|
connect_to_database!
|
8
7
|
Postjob::Migrations.migrate!
|
9
8
|
end
|
10
9
|
|
11
10
|
def db_unmigrate
|
12
|
-
|
11
|
+
if !force
|
12
|
+
confirm! <<~TXT
|
13
|
+
Really unmigrating database? This will destroy all data about postjobs!
|
14
|
+
(To prevent the need to confirm run with '--force'.)
|
15
|
+
TXT
|
16
|
+
end
|
13
17
|
|
14
18
|
connect_to_database!
|
15
19
|
Postjob::Migrations.unmigrate!
|
16
20
|
end
|
17
21
|
|
18
|
-
def db_remigrate
|
19
|
-
|
22
|
+
def db_remigrate(force: false)
|
23
|
+
if !force
|
24
|
+
confirm! <<~TXT
|
25
|
+
Really remigrating database? This will destroy all data about postjobs!
|
26
|
+
(To prevent the need to confirm run with '--force'.)
|
27
|
+
TXT
|
28
|
+
end
|
20
29
|
|
21
30
|
connect_to_database!
|
22
31
|
Postjob::Migrations.unmigrate!
|
23
32
|
Postjob::Migrations.migrate!
|
24
33
|
end
|
25
34
|
|
35
|
+
def confirm!(msg)
|
36
|
+
STDERR.puts <<~TXT
|
37
|
+
#{msg.chomp}
|
38
|
+
|
39
|
+
Press return to continue, ^C to cancel...
|
40
|
+
TXT
|
41
|
+
STDIN.gets
|
42
|
+
rescue Interrupt
|
43
|
+
raise "Cancelled by user"
|
44
|
+
end
|
45
|
+
|
26
46
|
private
|
27
47
|
|
28
48
|
USE_ACTIVE_RECORD = false
|
data/lib/postjob/cli/job.rb
CHANGED
@@ -4,7 +4,7 @@ module Postjob::CLI
|
|
4
4
|
# Adds a workflow to the job table, with name <workflow> and the given
|
5
5
|
# arguments.
|
6
6
|
#
|
7
|
-
# Note that the workflow will receive the arguments as strings and must be
|
7
|
+
# Note that the workflow will receive the arguments as strings and must be
|
8
8
|
# prepared to handle these.
|
9
9
|
def job_enqueue(workflow, *args, queue: "ruby", tags: nil)
|
10
10
|
connect_to_database!
|
@@ -22,7 +22,7 @@ module Postjob::CLI
|
|
22
22
|
full_job_id || logger.error("No such job: #{job_id}")
|
23
23
|
|
24
24
|
job_ids = Simple::SQL.all <<~SQL
|
25
|
-
SELECT id FROM postjob.postjobs
|
25
|
+
SELECT id FROM postjob.postjobs
|
26
26
|
WHERE (full_id LIKE '#{full_job_id}.%' OR full_id='#{full_job_id}')
|
27
27
|
AND status IN ('failed', 'err', 'timeout')
|
28
28
|
SQL
|
@@ -42,7 +42,7 @@ module Postjob::CLI
|
|
42
42
|
NOTIFY postjob_notifications
|
43
43
|
SQL
|
44
44
|
|
45
|
-
logger.warn "The following jobs have been reset: #{job_ids.join(
|
45
|
+
logger.warn "The following jobs have been reset: #{job_ids.join(', ')}"
|
46
46
|
end
|
47
47
|
|
48
48
|
private
|
data/lib/postjob/cli/ps.rb
CHANGED
@@ -57,7 +57,7 @@ module Postjob::CLI
|
|
57
57
|
limit = Integer(limit)
|
58
58
|
|
59
59
|
unless ids.empty?
|
60
|
-
ps_full
|
60
|
+
ps_full(*ids, limit: limit, tags: tags)
|
61
61
|
return
|
62
62
|
end
|
63
63
|
|
@@ -72,10 +72,10 @@ module Postjob::CLI
|
|
72
72
|
|
73
73
|
# Show all information about this job
|
74
74
|
def ps_show(id, *ids)
|
75
|
-
ids = ([
|
75
|
+
ids = ([id] + ids).map { |s| Integer(s) }
|
76
76
|
|
77
77
|
jobs = Simple::SQL.records <<~SQL, ids, into: Postjob::Job
|
78
|
-
|
78
|
+
SELECT * FROM postjob.postjobs WHERE id = ANY($1)
|
79
79
|
SQL
|
80
80
|
|
81
81
|
jobs.each do |job|
|
@@ -47,26 +47,16 @@ module Postjob::Queue::Notifications
|
|
47
47
|
# returns the maximum number of seconds to wait until the
|
48
48
|
# next runnable or timeoutable job comes up.
|
49
49
|
def time_to_next_job
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
queries.push <<~SQL
|
63
|
-
SELECT
|
64
|
-
EXTRACT(EPOCH FROM MIN(timing_out_at) - (now() at time zone 'utc'))
|
65
|
-
FROM #{TABLE_NAME}
|
66
|
-
WHERE status IN ('ready', 'sleep')
|
50
|
+
Simple::SQL.ask <<~SQL, Postjob::Registry.workflows_with_versions
|
51
|
+
SELECT EXTRACT(EPOCH FROM (MIN(next_event_at) - (now() at time zone 'utc'))) FROM (
|
52
|
+
SELECT MIN(timing_out_at) AS next_event_at
|
53
|
+
FROM #{TABLE_NAME}
|
54
|
+
WHERE status IN ('ready', 'sleep')
|
55
|
+
UNION
|
56
|
+
SELECT MIN(next_run_at) AS next_event_at
|
57
|
+
FROM #{TABLE_NAME}
|
58
|
+
WHERE status = 'ready' AND (workflow || workflow_version = ANY ($1))
|
59
|
+
) sq
|
67
60
|
SQL
|
68
|
-
|
69
|
-
timestamps = Simple::SQL.all(queries.join(" UNION "))
|
70
|
-
timestamps.compact.min
|
71
61
|
end
|
72
62
|
end
|
data/lib/postjob/queue.rb
CHANGED
@@ -99,7 +99,7 @@ module Postjob::Queue
|
|
99
99
|
|
100
100
|
SQL.ask <<~SQL, job.id, results
|
101
101
|
UPDATE #{TABLE_NAME}
|
102
|
-
SET results=$2, status='ok', next_run_at=NULL
|
102
|
+
SET results=$2, status='ok', next_run_at=NULL, error=NULL, error_message=NULL, error_backtrace=NULL
|
103
103
|
WHERE id=$1
|
104
104
|
SQL
|
105
105
|
|
@@ -136,7 +136,7 @@ module Postjob::Queue
|
|
136
136
|
# subtract 1, since this check runs *after* the current run was done,
|
137
137
|
# but before it was written to the database.
|
138
138
|
if status == :err && remaining_attempts(job) > 1
|
139
|
-
[ "
|
139
|
+
[ "err", next_run_at_fragment ]
|
140
140
|
elsif status == :timeout
|
141
141
|
[ "timeout", "NULL" ]
|
142
142
|
else
|
@@ -272,24 +272,6 @@ module Postjob::Queue
|
|
272
272
|
[workflow, workflow_method]
|
273
273
|
end
|
274
274
|
|
275
|
-
def runnable_sql_fragment
|
276
|
-
escaped_workflows_and_versions = Postjob::Registry.sql_escaped_workflows_and_versions
|
277
|
-
return "FALSE" if escaped_workflows_and_versions == ""
|
278
|
-
|
279
|
-
<<~SQL
|
280
|
-
next_run_at <= (now() at time zone 'utc')
|
281
|
-
AND status = 'ready'
|
282
|
-
AND ((workflow, workflow_version) IN (#{escaped_workflows_and_versions}))
|
283
|
-
SQL
|
284
|
-
end
|
285
|
-
|
286
|
-
def timing_out_sql_fragment
|
287
|
-
<<~SQL
|
288
|
-
timing_out_at <= (now() at time zone 'utc')
|
289
|
-
AND status IN ('ready', 'sleep')
|
290
|
-
SQL
|
291
|
-
end
|
292
|
-
|
293
275
|
public
|
294
276
|
|
295
277
|
def checkout_runnable
|
@@ -299,16 +281,16 @@ module Postjob::Queue
|
|
299
281
|
timing_out_at <= (now() at time zone 'utc') AS timed_out
|
300
282
|
FROM #{TABLE_NAME}
|
301
283
|
WHERE
|
302
|
-
(
|
284
|
+
(next_run_at <= (now() at time zone 'utc') AND status IN ('ready', 'err') AND workflow || workflow_version = ANY ($1))
|
303
285
|
OR
|
304
|
-
(
|
286
|
+
(timing_out_at <= (now() at time zone 'utc') AND status IN ('ready', 'err', 'sleep'))
|
305
287
|
ORDER BY (LEAST(next_run_at, timing_out_at))
|
306
288
|
FOR UPDATE SKIP LOCKED
|
307
289
|
LIMIT 1
|
308
290
|
SQL
|
309
291
|
|
310
292
|
SQL.transaction do
|
311
|
-
job = SQL.record sql, into: Job
|
293
|
+
job = SQL.record sql, Postjob::Registry.workflows_with_versions, into: Job
|
312
294
|
yield job if job
|
313
295
|
job
|
314
296
|
end
|
data/lib/postjob/registry.rb
CHANGED
@@ -6,35 +6,20 @@ module Postjob::Registry
|
|
6
6
|
instance.values.uniq
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
def sql_escaped_workflows_and_versions
|
13
|
-
@sql_escaped_workflows_and_versions ||= begin
|
14
|
-
instance.keys.map do |name, workflow_version|
|
15
|
-
escaped_name = sql_escape(name)
|
16
|
-
escaped_version = sql_escape(workflow_version)
|
17
|
-
"(#{escaped_name}, #{escaped_version})"
|
18
|
-
end.join(", ")
|
19
|
-
end
|
9
|
+
def workflows_with_versions
|
10
|
+
@workflows_with_versions ||= []
|
20
11
|
end
|
21
12
|
|
22
|
-
private
|
23
|
-
|
24
|
-
def sql_escape(s)
|
25
|
-
"'" + PG::Connection.escape_string(s) + "'"
|
26
|
-
end
|
27
|
-
|
28
|
-
public
|
29
|
-
|
30
13
|
# Used for tests
|
31
14
|
def reset! # :nodoc:
|
32
|
-
@instance = @
|
15
|
+
@instance = @workflows_with_versions = nil
|
33
16
|
end
|
34
17
|
|
35
18
|
def register(workflow, _options = {})
|
36
19
|
instance[[workflow.name, ""]] = workflow
|
37
20
|
instance[[workflow.name, workflow.workflow_version]] = workflow
|
21
|
+
|
22
|
+
workflows_with_versions << workflow.name << "#{workflow.name}#{workflow.workflow_version}"
|
38
23
|
end
|
39
24
|
|
40
25
|
def lookup!(name:, version:)
|
data/lib/postjob.rb
CHANGED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
# DO NOT TRY THIS IN THE REAL WORLD!
|
4
|
+
#
|
5
|
+
# This workflow uses a global value, FailureWorkflow.attempts, to count the
|
6
|
+
# number of attempts to run a workflow. This turns the workflow into a stateful
|
7
|
+
# affair WHICH BREAKS THE GENERAL CONTRACT OF POSTJOB.
|
8
|
+
module FailureWorkflow
|
9
|
+
extend self
|
10
|
+
|
11
|
+
attr_accessor :attempts
|
12
|
+
|
13
|
+
def run(number_of_failing_attempts)
|
14
|
+
self.attempts += 1
|
15
|
+
if self.attempts <= number_of_failing_attempts
|
16
|
+
raise "FailureWorkflow failed"
|
17
|
+
end
|
18
|
+
|
19
|
+
"result"
|
20
|
+
end
|
21
|
+
|
22
|
+
Postjob.register_workflow self
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "error states" do
|
26
|
+
before do
|
27
|
+
FailureWorkflow.attempts = 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_job
|
31
|
+
TestHelper.load_job(job_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
let!(:job_id) { Postjob.enqueue!("FailureWorkflow", 1) }
|
35
|
+
|
36
|
+
context "when running a job that runs into an exception" do
|
37
|
+
before do
|
38
|
+
Postjob.process_all
|
39
|
+
end
|
40
|
+
|
41
|
+
it "sets the job's status to err" do
|
42
|
+
expect(load_job.status).to eq("err")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "sets the job's error information" do
|
46
|
+
expect(load_job.error_message).to eq("FailureWorkflow failed")
|
47
|
+
expect(load_job.error).to eq("RuntimeError")
|
48
|
+
expect(load_job.error_backtrace).to be_a(Array)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when rerunning the job so that it succeeds" do
|
53
|
+
before do
|
54
|
+
while Postjob.process_all > 0
|
55
|
+
sleep 0.1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "sets the job's status to ok" do
|
60
|
+
expect(load_job.status).to eq("ok")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "sets the job's result" do
|
64
|
+
expect(load_job.result).to eq("result")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "cleared out the error entries" do
|
68
|
+
expect(load_job.error_message).to be_nil
|
69
|
+
expect(load_job.error).to be_nil
|
70
|
+
expect(load_job.error_backtrace).to be_nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/spec/postjob/run_spec.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.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -236,6 +236,7 @@ files:
|
|
236
236
|
- lib/postjob/workflow.rb
|
237
237
|
- spec/postjob/enqueue_spec.rb
|
238
238
|
- spec/postjob/full_workflow_spec.rb
|
239
|
+
- spec/postjob/job_control/error_status_spec.rb
|
239
240
|
- spec/postjob/job_control/manual_spec.rb
|
240
241
|
- spec/postjob/job_control/max_attempts_spec.rb
|
241
242
|
- spec/postjob/job_control/timeout_spec.rb
|