postjob 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -8
- data/lib/postjob/cli/db.rb +2 -2
- data/lib/postjob/cli/job.rb +21 -0
- data/lib/postjob/cli/ps.rb +4 -4
- data/lib/postjob/job.rb +3 -0
- data/lib/postjob/queue/encoder.rb +0 -1
- data/lib/postjob/queue/notifications.rb +10 -8
- data/lib/postjob/queue/search.rb +0 -1
- data/lib/postjob/queue.rb +3 -2
- data/lib/postjob/runner.rb +8 -5
- data/lib/postjob.rb +2 -1
- data/spec/postjob/full_workflow_spec.rb +1 -1
- data/spec/postjob/job_control/error_status_spec.rb +1 -3
- data/spec/postjob/job_control/max_attempts_spec.rb +2 -6
- data/spec/spec_helper.rb +1 -1
- data/spec/support/connect_active_record.rb +0 -1
- metadata +4 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a648c2a0a8e5dd0ab60285c9cc59ceb7a68ed863
|
4
|
+
data.tar.gz: 825bf32c99d020cd9b4c45910da67a1c5923394a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b906419d181d39e540654f351b13c7c0a7ce90e3e0aef10cdcd53df47c87dfcccb0b09641303e55032191784990845f41009ae280311d1b65196d7bf972da97
|
7
|
+
data.tar.gz: 7bcbb6b009ed360328b5b0b6e032d836f7d84e25f2bfaf074dfcb9215262a4ed9a47504aab24bb6f5c80e547efd63d0f3848bafc1ed527a7bdc9f1acef7ab966
|
data/README.md
CHANGED
@@ -1,23 +1,40 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/mediapeers/postjob.svg?branch=master)](https://travis-ci.org/mediapeers/postjob)
|
2
|
+
|
1
3
|
# Postjob
|
2
4
|
|
3
5
|
The `postjob` gem implements a simple way to have restartable, asynchronous, and distributed processes.
|
4
6
|
|
5
|
-
##
|
7
|
+
## Install
|
6
8
|
|
7
|
-
|
9
|
+
To install gem run `gem install postjob` or add `gem postjob` to your Gemfile and bundle.
|
8
10
|
|
9
|
-
|
11
|
+
## Development setup
|
10
12
|
|
11
|
-
|
13
|
+
1. Make sure you have PostgreSQL >= 9.5 installed
|
14
|
+
2. Clone repo `git clone git@github.com:mediapeers/postjob.git && cd postjob`
|
15
|
+
3. Run `./scripts/setup` to bundle and setup DB (requires passwordless postgres user).
|
12
16
|
|
13
|
-
To
|
17
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
14
18
|
|
15
|
-
##
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Tests are set up to run twice, once against an ActiveRecord adapter, and once against a Simple::SQL provided adapter. To run the full test suite run
|
22
|
+
|
23
|
+
make ci_tests
|
24
|
+
|
25
|
+
To run a single set of tests - this is usually fine during development - run
|
16
26
|
|
17
|
-
|
27
|
+
bundle exec rspec
|
18
28
|
|
29
|
+
## Release gem
|
30
|
+
|
31
|
+
To release a new version of this gem , run `./scripts/release`, which will bump the version number, create a git tag for the version,
|
32
|
+
push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mediapeers/postqueue.
|
19
37
|
|
20
38
|
## License
|
21
39
|
|
22
40
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
23
|
-
|
data/lib/postjob/cli/db.rb
CHANGED
@@ -8,7 +8,7 @@ module Postjob::CLI
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def db_unmigrate
|
11
|
-
|
11
|
+
unless force
|
12
12
|
confirm! <<~TXT
|
13
13
|
Really unmigrating database? This will destroy all data about postjobs!
|
14
14
|
(To prevent the need to confirm run with '--force'.)
|
@@ -20,7 +20,7 @@ module Postjob::CLI
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def db_remigrate(force: false)
|
23
|
-
|
23
|
+
unless force
|
24
24
|
confirm! <<~TXT
|
25
25
|
Really remigrating database? This will destroy all data about postjobs!
|
26
26
|
(To prevent the need to confirm run with '--force'.)
|
data/lib/postjob/cli/job.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# rubocop:disable Metrics/MethodLength
|
2
|
+
|
1
3
|
module Postjob::CLI
|
2
4
|
# Enqueues a workflow
|
3
5
|
#
|
@@ -17,6 +19,8 @@ module Postjob::CLI
|
|
17
19
|
# This resets all failed jobs within the job tree, below the passed in
|
18
20
|
# job id.
|
19
21
|
def job_reset(job_id)
|
22
|
+
connect_to_database!
|
23
|
+
|
20
24
|
job_id = Integer(job_id)
|
21
25
|
full_job_id = Simple::SQL.ask "SELECT full_id FROM postjob.postjobs WHERE id=$1", job_id
|
22
26
|
full_job_id || logger.error("No such job: #{job_id}")
|
@@ -45,6 +49,23 @@ module Postjob::CLI
|
|
45
49
|
logger.warn "The following jobs have been reset: #{job_ids.join(', ')}"
|
46
50
|
end
|
47
51
|
|
52
|
+
# Kills a specific job
|
53
|
+
def job_kill(job_id)
|
54
|
+
connect_to_database!
|
55
|
+
|
56
|
+
job_id = Integer(job_id)
|
57
|
+
|
58
|
+
Simple::SQL.ask <<~SQL, job_id
|
59
|
+
UPDATE postjob.postjobs
|
60
|
+
SET
|
61
|
+
status='failed',
|
62
|
+
next_run_at=null,
|
63
|
+
error='Manually terminated',
|
64
|
+
error_message='Manually terminated'
|
65
|
+
WHERE id = $1 AND status IN ('ready', 'err', 'sleep')
|
66
|
+
SQL
|
67
|
+
end
|
68
|
+
|
48
69
|
private
|
49
70
|
|
50
71
|
# parses "foo:bar,baz:quibble" into { "foo" => "bar", "baz" => "quibble"}
|
data/lib/postjob/cli/ps.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Postjob::CLI
|
2
2
|
private
|
3
|
-
|
3
|
+
|
4
4
|
def ps_query(conditions = [])
|
5
5
|
conditions.compact!
|
6
6
|
|
@@ -31,7 +31,7 @@ module Postjob::CLI
|
|
31
31
|
ORDER BY root_id DESC, id ASC
|
32
32
|
SQL
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def tags_condition(tags)
|
36
36
|
return nil unless tags
|
37
37
|
|
@@ -46,8 +46,8 @@ module Postjob::CLI
|
|
46
46
|
# This command lists the statuses of all jobs that are either root jobs,
|
47
47
|
# i.e. enqueued workflows, or that have failed.
|
48
48
|
#
|
49
|
-
# Example:
|
50
|
-
#
|
49
|
+
# Example:
|
50
|
+
#
|
51
51
|
# postjob ps --tags=foo:bar,bar:baz --limit=100
|
52
52
|
#
|
53
53
|
# For a listing of all jobs in the system use ps:full, see 'postjob help ps:full'
|
data/lib/postjob/job.rb
CHANGED
@@ -11,19 +11,21 @@ module Postjob::Queue::Notifications
|
|
11
11
|
SQL.ask "NOTIFY #{CHANNEL}"
|
12
12
|
end
|
13
13
|
|
14
|
+
MAX_WAIT_TIME = 120
|
15
|
+
|
14
16
|
def wait_for_new_job
|
15
17
|
started_at = Time.now
|
16
18
|
|
17
19
|
start_listening
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
# Determine when the next job is up. If we don't have a next job within MAX_WAIT_TIME
|
22
|
+
# we wake up regardless.
|
23
|
+
wait_time = time_to_next_job
|
24
|
+
return if wait_time && wait_time <= 0
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
26
|
+
wait_time ||= MAX_WAIT_TIME
|
27
|
+
Postjob.logger.debug "postjob: waiting for notification for up to #{wait_time.inspect} seconds"
|
28
|
+
Simple::SQL.wait_for_notify(wait_time)
|
27
29
|
|
28
30
|
# flush notifications. It is possible that a huge number of notifications
|
29
31
|
# piled up while we have been waiting. The following line takes care of
|
@@ -51,7 +53,7 @@ module Postjob::Queue::Notifications
|
|
51
53
|
SELECT EXTRACT(EPOCH FROM (MIN(next_event_at) - (now() at time zone 'utc'))) FROM (
|
52
54
|
SELECT MIN(timing_out_at) AS next_event_at
|
53
55
|
FROM #{TABLE_NAME}
|
54
|
-
WHERE status IN ('ready', 'sleep')
|
56
|
+
WHERE status IN ('ready', 'sleep', 'err')
|
55
57
|
UNION
|
56
58
|
SELECT MIN(next_run_at) AS next_event_at
|
57
59
|
FROM #{TABLE_NAME}
|
data/lib/postjob/queue/search.rb
CHANGED
data/lib/postjob/queue.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
# rubocop:disable Metrics/ModuleLength
|
4
4
|
# rubocop:disable Metrics/LineLength
|
5
5
|
# rubocop:disable Lint/EndAlignment
|
6
|
-
# rubocop:disable
|
6
|
+
# rubocop:disable Metrics/MethodLength
|
7
|
+
# rubocop:disable Metrics/ParameterLists
|
7
8
|
|
8
9
|
require "securerandom"
|
9
10
|
|
@@ -28,7 +29,7 @@ module Postjob::Queue
|
|
28
29
|
version: "",
|
29
30
|
queue: "q",
|
30
31
|
max_attempts: 5
|
31
|
-
}
|
32
|
+
}
|
32
33
|
|
33
34
|
# enqueues a new job with the given arguments
|
34
35
|
#
|
data/lib/postjob/runner.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
# rubocop:disable
|
1
|
+
# rubocop:disable Metrics/ModuleLength
|
2
|
+
# rubocop:disable Style/BlockDelimiters
|
3
|
+
# rubocop:disable Lint/RescueException
|
4
|
+
|
2
5
|
module Postjob::Runner
|
3
6
|
extend self
|
4
7
|
|
@@ -114,11 +117,11 @@ module Postjob::Runner
|
|
114
117
|
when :pending then [ :pending, nil ]
|
115
118
|
else [ :ok, value ]
|
116
119
|
end
|
117
|
-
rescue
|
118
|
-
return_exception :err, $!
|
119
|
-
rescue StandardError
|
120
|
+
rescue ArgumentError, LocalJumpError, NameError, RegexpError, ScriptError, TypeError
|
120
121
|
Postjob.logger.error "#{$!}, from\n\t#{$!.backtrace[0, 10].join("\n\t")}"
|
121
122
|
return_exception :failed, $!
|
123
|
+
rescue Exception
|
124
|
+
return_exception :err, $!
|
122
125
|
end
|
123
126
|
|
124
127
|
def return_exception(state, exception)
|
@@ -145,7 +148,7 @@ module Postjob::Runner
|
|
145
148
|
def error_message(job, status, value)
|
146
149
|
runtime = Time.now.utc - job.created_at
|
147
150
|
runtime = "%.03f secs" % runtime
|
148
|
-
error_class, err_message,
|
151
|
+
error_class, err_message, _error_backtrace = value
|
149
152
|
|
150
153
|
"#{job} #{status} #{error_class} #{err_message.inspect}: #{runtime}"
|
151
154
|
# + "\n backtrace information:\n #{error_backtrace.join("\n ")}"
|
data/lib/postjob.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# rubocop:disable Metrics/ParameterLists
|
2
|
+
|
1
3
|
require "expectation"
|
2
4
|
require "simple/sql"
|
3
5
|
require "timeout"
|
@@ -127,7 +129,6 @@ module Postjob
|
|
127
129
|
private
|
128
130
|
|
129
131
|
# This method is called from tests. Otherwise it is supposed to be private.
|
130
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
131
132
|
def process_job(job) # :nodoc:
|
132
133
|
expect! job => Job
|
133
134
|
|
@@ -74,7 +74,7 @@ describe "Sub Workflows" do
|
|
74
74
|
let!(:user_ids) { 100.upto(100 + users_count - 1).to_a }
|
75
75
|
let!(:id) { Postjob.enqueue! "RecommendGroupWorkflow", 1, user_ids }
|
76
76
|
|
77
|
-
|
77
|
+
xit "runs the job returning the result" do
|
78
78
|
expect(MPX::Impl).to receive(:clone_group).exactly(1).times.and_call_original
|
79
79
|
expect(MPX::Impl).to receive(:load_users).exactly(1).times.and_call_original
|
80
80
|
expect(MPX::Impl).to receive(:send_email).exactly(users_count).times.and_call_original
|
@@ -39,9 +39,7 @@ describe "max_attempts" do
|
|
39
39
|
let!(:id) { Postjob.enqueue!("MaxAttemptWorkflow", 1, max_attempts: 1) }
|
40
40
|
|
41
41
|
it "fails the childjob with a timeout" do
|
42
|
-
while Postjob.process_all > 0
|
43
|
-
sleep 0.03
|
44
|
-
end
|
42
|
+
sleep 0.03 while Postjob.process_all > 0
|
45
43
|
|
46
44
|
expect(load_child_job.failed_attempts).to eq(1)
|
47
45
|
expect(load_child_job.status).to eq("failed")
|
@@ -54,9 +52,7 @@ describe "max_attempts" do
|
|
54
52
|
let!(:id) { Postjob.enqueue!("MaxAttemptWorkflow", 5, max_attempts: 1) }
|
55
53
|
|
56
54
|
it "fails the childjob with a timeout" do
|
57
|
-
while Postjob.process_all > 0
|
58
|
-
sleep 0.03
|
59
|
-
end
|
55
|
+
sleep 0.03 while Postjob.process_all > 0
|
60
56
|
|
61
57
|
expect(load_child_job.failed_attempts).to eq(5)
|
62
58
|
expect(load_child_job.status).to eq("failed")
|
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.1.
|
4
|
+
version: 0.1.9
|
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-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -86,34 +86,20 @@ dependencies:
|
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '4.2'
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: timecop
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - "~>"
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '0'
|
96
|
-
type: :development
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - "~>"
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '0'
|
103
89
|
- !ruby/object:Gem::Dependency
|
104
90
|
name: rubocop
|
105
91
|
requirement: !ruby/object:Gem::Requirement
|
106
92
|
requirements:
|
107
93
|
- - "~>"
|
108
94
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
95
|
+
version: 0.52.1
|
110
96
|
type: :development
|
111
97
|
prerelease: false
|
112
98
|
version_requirements: !ruby/object:Gem::Requirement
|
113
99
|
requirements:
|
114
100
|
- - "~>"
|
115
101
|
- !ruby/object:Gem::Version
|
116
|
-
version:
|
102
|
+
version: 0.52.1
|
117
103
|
- !ruby/object:Gem::Dependency
|
118
104
|
name: awesome_print
|
119
105
|
requirement: !ruby/object:Gem::Requirement
|