jober 0.3 → 0.3.5
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/jober.gemspec +4 -4
- data/lib/jober/abstract_task.rb +14 -3
- data/lib/jober/ar_loop.rb +11 -5
- data/lib/jober/threaded_manager.rb +16 -4
- data/lib/jober/version.rb +1 -1
- data/spec/ar_loop_spec.rb +11 -0
- data/spec/stats_spec.rb +2 -0
- data/spec/task_loop_spec.rb +46 -3
- metadata +22 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9dda52df02d094768a2a3dd014f9a26f2858cdd1
|
4
|
+
data.tar.gz: 15dc813ba49402330112935dffee45b5e9d454c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b15bae2a5b73f36802a68b857079a98568f84da046fdbcb2cd562d0dd2bfcf209a9cebd45d680138c6bbdb373572ad80a1b3d579324ce9f228a9f7151f2b1629
|
7
|
+
data.tar.gz: 15fc13a7c10848a56b426928aaead2c0277ffe13696703e6b02a146b7212682c5f6b5d5f55a7b7848ed1b80086f0dc387fbc7c5136c92896527a714a56e9e860
|
data/jober.gemspec
CHANGED
@@ -20,9 +20,9 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency 'redis'
|
22
22
|
|
23
|
-
spec.add_development_dependency "
|
24
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rake"
|
25
24
|
spec.add_development_dependency "rspec"
|
26
|
-
spec.add_development_dependency "activerecord"
|
27
|
-
spec.add_development_dependency "sqlite3"
|
25
|
+
spec.add_development_dependency "activerecord", '~> 3.2'
|
26
|
+
spec.add_development_dependency "sqlite3-ruby"
|
27
|
+
spec.add_development_dependency "i18n", '~> 0.6.0'
|
28
28
|
end
|
data/lib/jober/abstract_task.rb
CHANGED
@@ -24,8 +24,7 @@ class Jober::AbstractTask
|
|
24
24
|
attr_accessor :short_name
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
attr_reader :worker_id, :workers_count
|
27
|
+
attr_reader :finished, :stopped, :worker_id, :workers_count
|
29
28
|
|
30
29
|
def self.inherited(base)
|
31
30
|
Jober.add_class(base)
|
@@ -53,7 +52,13 @@ class Jober::AbstractTask
|
|
53
52
|
run
|
54
53
|
self.class.write_timestamp(:finished)
|
55
54
|
self.class.del_timestamp(:crashed)
|
55
|
+
if @stopped
|
56
|
+
self.class.write_timestamp(:stopped)
|
57
|
+
else
|
58
|
+
self.class.del_timestamp(:stopped)
|
59
|
+
end
|
56
60
|
info "<= end (in #{Time.now - @start_at})"
|
61
|
+
@finished = true
|
57
62
|
self
|
58
63
|
rescue Object
|
59
64
|
self.class.write_timestamp(:crashed)
|
@@ -68,7 +73,8 @@ class Jober::AbstractTask
|
|
68
73
|
(finished = self.class.read_timestamp(:finished)) &&
|
69
74
|
(Time.now - finished < self.class.get_interval) &&
|
70
75
|
!self.class.pop_skip_delay_flag! &&
|
71
|
-
!@skip_delay
|
76
|
+
!@skip_delay &&
|
77
|
+
!self.class.read_timestamp(:stopped)
|
72
78
|
|
73
79
|
sleeping(self.class.get_interval - (Time.now - finished))
|
74
80
|
end
|
@@ -98,6 +104,7 @@ class Jober::AbstractTask
|
|
98
104
|
|
99
105
|
def stop!
|
100
106
|
@stopped = true
|
107
|
+
self.class.write_timestamp(:stopped)
|
101
108
|
end
|
102
109
|
|
103
110
|
private
|
@@ -156,4 +163,8 @@ private
|
|
156
163
|
end
|
157
164
|
end
|
158
165
|
|
166
|
+
def self.stats
|
167
|
+
Jober.stats[self.short_name]
|
168
|
+
end
|
169
|
+
|
159
170
|
end
|
data/lib/jober/ar_loop.rb
CHANGED
@@ -16,34 +16,40 @@ class Jober::ARLoop < Jober::Task
|
|
16
16
|
def run
|
17
17
|
prox = proxy
|
18
18
|
|
19
|
+
prefix = ''
|
20
|
+
|
19
21
|
if @worker_id && @workers_count && @workers_count > 1 && !@opts[:no_auto_proxy]
|
20
22
|
cond = "id % #{@workers_count} = #{@worker_id}"
|
21
23
|
prox = prox.where(cond)
|
24
|
+
prefix += "(#{cond}) "
|
22
25
|
info { "sharding enabled '#{cond}'" }
|
23
26
|
end
|
24
27
|
|
25
28
|
last_batch_id = if (_last_batch_id = get_store("lastbatch")) && !@opts[:no_last_batch]
|
26
|
-
info { "
|
29
|
+
info { "Finded last_batch_id #{_last_batch_id} so start with it!" }
|
30
|
+
prefix += "(#{_last_batch_id}:) "
|
27
31
|
_last_batch_id
|
28
32
|
end
|
29
33
|
|
30
34
|
prox = prox.where(@opts[:where]) if @opts[:where]
|
31
35
|
|
32
36
|
cnt = 0
|
33
|
-
count = prox.count
|
34
|
-
info { "full count to process #{count}" }
|
37
|
+
count = last_batch_id ? prox.where("id > ?", last_batch_id).count : prox.count
|
38
|
+
info { "#{prefix}full count to process #{count}" }
|
35
39
|
|
36
40
|
h = {:batch_size => self.class.get_batch_size}
|
37
41
|
h[:start] = last_batch_id + 1 if last_batch_id
|
38
42
|
prox.find_in_batches(h) do |batch|
|
39
43
|
res = perform(batch)
|
40
44
|
cnt += batch.size
|
41
|
-
info { "process batch #{res.inspect}, #{cnt} from #{count}, lastid #{batch.last.id}" }
|
45
|
+
info { "#{prefix}process batch #{res.inspect}, #{cnt} from #{count}, lastid #{batch.last.id}" }
|
42
46
|
set_store("lastbatch", batch.last.id)
|
43
47
|
break if stopped
|
44
48
|
end
|
45
49
|
|
46
|
-
|
50
|
+
reset_last_batch_id unless stopped
|
51
|
+
|
52
|
+
info { "#{prefix}processed total #{cnt}" }
|
47
53
|
end
|
48
54
|
|
49
55
|
def reset_last_batch_id
|
@@ -11,7 +11,7 @@ class Jober::ThreadedManager
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def initialize(klasses = nil, opts = {})
|
14
|
-
@klasses = klasses || Jober.classes
|
14
|
+
@klasses = Array(klasses || Jober.classes)
|
15
15
|
@stopped = false
|
16
16
|
@objects = @klasses.map do |klass|
|
17
17
|
if klass.is_a?(String)
|
@@ -24,7 +24,7 @@ class Jober::ThreadedManager
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def run_loop
|
27
|
-
info { "run loop for #{@klasses}, in threads: #{@objects.length}" }
|
27
|
+
info { "run loop for #{@klasses.inspect}, in threads: #{@objects.length}" }
|
28
28
|
@threads = @objects.map { |obj| make_thread(obj) }
|
29
29
|
|
30
30
|
# set signals
|
@@ -39,10 +39,18 @@ class Jober::ThreadedManager
|
|
39
39
|
# send stop to all objects
|
40
40
|
@objects.each(&:stop!)
|
41
41
|
|
42
|
+
# sleep a little
|
43
|
+
sleep(0.2)
|
44
|
+
|
42
45
|
# sleep a little to give time for threads to quit
|
43
46
|
wait_for_kill(default_sleep.to_f)
|
44
47
|
|
45
|
-
|
48
|
+
names = not_finished_objects_names
|
49
|
+
if names.empty?
|
50
|
+
info { "quit!" }
|
51
|
+
else
|
52
|
+
info { "quit! and force killing #{names.inspect}" }
|
53
|
+
end
|
46
54
|
|
47
55
|
# kill all threads, if they still alive
|
48
56
|
@threads.select(&:alive?).each(&:kill)
|
@@ -61,8 +69,12 @@ private
|
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
72
|
+
def not_finished_objects_names
|
73
|
+
@objects.reject(&:finished).map { |o| o.class.name }
|
74
|
+
end
|
75
|
+
|
64
76
|
def wait_for_kill(interval)
|
65
|
-
info { "waiting quiting jobs for %.1fm ..." % [interval / 60.0] }
|
77
|
+
info { "waiting quiting jobs (#{not_finished_objects_names.inspect}) for %.1fm ..." % [interval / 60.0] }
|
66
78
|
Timeout.timeout(interval.to_f) do
|
67
79
|
loop do
|
68
80
|
sleep 0.3
|
data/lib/jober/version.rb
CHANGED
data/spec/ar_loop_spec.rb
CHANGED
@@ -30,6 +30,7 @@ end
|
|
30
30
|
|
31
31
|
conn = { 'adapter' => 'sqlite3', 'database' => File.dirname(__FILE__) + "/test.db" }
|
32
32
|
ActiveRecord::Base.establish_connection conn
|
33
|
+
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
33
34
|
|
34
35
|
def pg_create_schema
|
35
36
|
ActiveRecord::Migration.verbose = false
|
@@ -115,4 +116,14 @@ describe "ARLoop" do
|
|
115
116
|
SO["names"].size.should == 66
|
116
117
|
end
|
117
118
|
|
119
|
+
it "should not start from lastbatch if task was finished by itself, not by stop" do
|
120
|
+
my = MyAR2.new
|
121
|
+
my.execute
|
122
|
+
SO["names"].size.should == 46
|
123
|
+
|
124
|
+
# should start from zero
|
125
|
+
my = MyAR2.new
|
126
|
+
my.execute
|
127
|
+
SO["names"].size.should == 46 + 46
|
128
|
+
end
|
118
129
|
end
|
data/spec/stats_spec.rb
CHANGED
data/spec/task_loop_spec.rb
CHANGED
@@ -31,6 +31,16 @@ class Loop2 < Jober::Task
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
class Loop3 < Jober::Task
|
35
|
+
interval 3
|
36
|
+
def perform
|
37
|
+
c = 0
|
38
|
+
loop { sleep 1; c += 1; break if stopped || c > 4 }
|
39
|
+
SO["y"] ||= 0
|
40
|
+
SO["y"] += 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
34
44
|
describe "Task" do
|
35
45
|
it "interval interval should be inherited" do
|
36
46
|
AA1.get_interval.should == 10
|
@@ -68,7 +78,7 @@ describe "Task" do
|
|
68
78
|
l.execute
|
69
79
|
t = Thread.new { l.run_loop }
|
70
80
|
sleep 2
|
71
|
-
l.
|
81
|
+
l.stop!
|
72
82
|
sleep 0.3
|
73
83
|
SO["y"].should == 1
|
74
84
|
end
|
@@ -79,7 +89,7 @@ describe "Task" do
|
|
79
89
|
Loop2.skip_delay!
|
80
90
|
t = Thread.new { l.run_loop }
|
81
91
|
sleep 2
|
82
|
-
l.
|
92
|
+
l.stop!
|
83
93
|
sleep 0.3
|
84
94
|
SO["y"].should == 2
|
85
95
|
end
|
@@ -89,11 +99,44 @@ describe "Task" do
|
|
89
99
|
l.execute
|
90
100
|
t = Thread.new { l.run_loop }
|
91
101
|
sleep 2
|
92
|
-
l.
|
102
|
+
l.stop!
|
93
103
|
sleep 0.3
|
94
104
|
SO["y"].should == 2
|
95
105
|
end
|
96
106
|
|
107
|
+
describe "task was finished by itself or by stop!" do
|
108
|
+
it "if was finished by itself" do
|
109
|
+
l = Loop3.new
|
110
|
+
l.execute
|
111
|
+
SO["y"].should == 1
|
112
|
+
|
113
|
+
# next run should wait for 3 seconds
|
114
|
+
l = Loop3.new
|
115
|
+
t = Thread.new { l.run_loop }
|
116
|
+
sleep 2
|
117
|
+
l.stop!
|
118
|
+
sleep 0.3
|
119
|
+
SO["y"].should == 1
|
120
|
+
end
|
121
|
+
|
122
|
+
it "was stopped in middle, should start next imidiately" do
|
123
|
+
l = Loop3.new
|
124
|
+
t = Thread.new { l.execute }
|
125
|
+
sleep 2
|
126
|
+
l.stop!
|
127
|
+
sleep 0.3
|
128
|
+
SO["y"].should == 1
|
129
|
+
|
130
|
+
# next run should wait for 3 seconds
|
131
|
+
l = Loop3.new
|
132
|
+
t = Thread.new { l.run_loop }
|
133
|
+
sleep 2
|
134
|
+
l.stop!
|
135
|
+
sleep 0.3
|
136
|
+
SO["y"].should == 2
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
97
140
|
it "skip_delay!" do
|
98
141
|
Loop2.pop_skip_delay_flag!.should == false
|
99
142
|
Loop2.skip_delay!
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jober
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "'Konstantin Makarchev'"
|
@@ -25,49 +25,49 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: activerecord
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '3.2'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '3.2'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: sqlite3-ruby
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,19 +81,19 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: i18n
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 0.6.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 0.6.0
|
97
97
|
description: Simple background jobs, queues.
|
98
98
|
email:
|
99
99
|
- "'kostya27@gmail.com'"
|