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 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'"