jober 0.3 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ddcfe15a02c6711edc74697daa7f399569561ee1
4
- data.tar.gz: 7d1fb585d8bd3e1307231d2a4eb7944102cd9fac
3
+ metadata.gz: 9dda52df02d094768a2a3dd014f9a26f2858cdd1
4
+ data.tar.gz: 15dc813ba49402330112935dffee45b5e9d454c5
5
5
  SHA512:
6
- metadata.gz: 274b9cf0c10120c4e0b0f20ef198b54d6d449c9e0be5248a88c59bc0e05d21adeff4aa33a54d923c3ecd6964b319b0e8ec70cc5d7d76a2c95480a82c80e787ee
7
- data.tar.gz: c90c327dfa205e59dcf083d07c040e0d12a102a2fc0fcfec6705ebd0fd13dfc4b426df64a329bd7ba0ce007c95ffc6ae4698c33a4625b7537084f827cdb3b7b6
6
+ metadata.gz: b15bae2a5b73f36802a68b857079a98568f84da046fdbcb2cd562d0dd2bfcf209a9cebd45d680138c6bbdb373572ad80a1b3d579324ce9f228a9f7151f2b1629
7
+ data.tar.gz: 15fc13a7c10848a56b426928aaead2c0277ffe13696703e6b02a146b7212682c5f6b5d5f55a7b7848ed1b80086f0dc387fbc7c5136c92896527a714a56e9e860
@@ -20,9 +20,9 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency 'redis'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.7"
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
@@ -24,8 +24,7 @@ class Jober::AbstractTask
24
24
  attr_accessor :short_name
25
25
  end
26
26
 
27
- attr_accessor :stopped
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
@@ -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 { "found last batch id #{last_batch_id} so start with it!" }
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
- info { "processed total #{cnt}" }
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
- info { "quit!" }
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
@@ -1,3 +1,3 @@
1
1
  module Jober
2
- VERSION = "0.3"
2
+ VERSION = "0.3.5"
3
3
  end
@@ -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
@@ -31,5 +31,7 @@ describe "Stats" do
31
31
  h['my2'][:started].should be
32
32
  h['my2'][:finished].should be
33
33
  h['my2'][:duration].should be_within(0.1).of(0.0)
34
+
35
+ MyQueue2.stats[:started].should be
34
36
  end
35
37
  end
@@ -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.stopped = true
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.stopped = true
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.stopped = true
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: '0.3'
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: bundler
28
+ name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.7'
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: '1.7'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
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: '10.0'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec
56
+ name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
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: '0'
68
+ version: '3.2'
69
69
  - !ruby/object:Gem::Dependency
70
- name: activerecord
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: sqlite3
84
+ name: i18n
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
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: '0'
96
+ version: 0.6.0
97
97
  description: Simple background jobs, queues.
98
98
  email:
99
99
  - "'kostya27@gmail.com'"