adrian 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,16 +2,17 @@ require 'adrian/queue'
2
2
 
3
3
  module Adrian
4
4
  class ArrayQueue < Queue
5
- def initialize(array = [])
5
+ def initialize(array = [], options = {})
6
+ super(options)
6
7
  @array = array.map { |item| wrap_item(item) }
7
8
  @mutex = Mutex.new
8
9
  end
9
10
 
10
- def pop
11
+ def pop_item
11
12
  @mutex.synchronize { @array.shift }
12
13
  end
13
14
 
14
- def push(item)
15
+ def push_item(item)
15
16
  item = wrap_item(item)
16
17
  @mutex.synchronize { @array << item }
17
18
  self
@@ -3,6 +3,7 @@ require 'adrian/queue'
3
3
  module Adrian
4
4
  class CompositeQueue < Queue
5
5
  def initialize(*queues)
6
+ super()
6
7
  @queues = queues.flatten
7
8
  end
8
9
 
@@ -19,6 +19,7 @@ module Adrian
19
19
  # 1. It's much simpler than introducing a seperate monitoring process to handle lock expiry.
20
20
  # 2. This is an acceptable and rare event. e.g. it only happens when the process working on the item crashes without being able to release the lock
21
21
  def initialize(options = {})
22
+ super
22
23
  @available_path = options.fetch(:path)
23
24
  @reserved_path = options.fetch(:reserved_path, default_reserved_path)
24
25
  @logger = options[:logger]
@@ -26,7 +27,7 @@ module Adrian
26
27
  filters << Filters::Delay.new(:duration => options[:delay]) if options[:delay]
27
28
  end
28
29
 
29
- def pop
30
+ def pop_item
30
31
  items.each do |item|
31
32
  return item if reserve(item)
32
33
  end
@@ -34,7 +35,7 @@ module Adrian
34
35
  nil
35
36
  end
36
37
 
37
- def push(value)
38
+ def push_item(value)
38
39
  item = wrap_item(value)
39
40
  item.move(available_path)
40
41
  item.touch
@@ -25,7 +25,17 @@ module Adrian
25
25
  @running = true
26
26
 
27
27
  while @running do
28
- if item = queue.pop
28
+ begin
29
+ item = queue.pop
30
+ rescue Adrian::Queue::ItemTooOldError => e
31
+ if handler = @failure_handler.handle(e)
32
+ handler.call(e.item, nil, e)
33
+ end
34
+ item = nil
35
+ next
36
+ end
37
+
38
+ if item
29
39
  delegate_work(item, worker_class)
30
40
  else
31
41
  if @stop_when_done
data/lib/adrian/queue.rb CHANGED
@@ -1,11 +1,45 @@
1
1
  module Adrian
2
2
  class Queue
3
+ class ItemTooOldError < RuntimeError
4
+ attr_reader :item, :queue
5
+
6
+ def initialize(item, queue)
7
+ super()
8
+ @item = item
9
+ @queue = queue
10
+ end
11
+ end
12
+
13
+ def initialize(options = {})
14
+ @options = options
15
+ end
16
+
3
17
  def pop
4
- raise "#{self.class.name}#pop is not defined"
18
+ verify_age!(pop_item)
5
19
  end
6
20
 
7
21
  def push(item)
8
- raise "#{self.class.name}#push is not defined"
22
+ push_item(item)
23
+ end
24
+
25
+ def verify_age!(item)
26
+ if item && max_age && item.age > max_age
27
+ raise ItemTooOldError.new(item, self)
28
+ end
29
+
30
+ item
31
+ end
32
+
33
+ def max_age
34
+ @max_age ||= @options[:max_age]
35
+ end
36
+
37
+ def pop_item
38
+ raise "#{self.class.name}#pop_item is not defined"
39
+ end
40
+
41
+ def push_item(item)
42
+ raise "#{self.class.name}#push_item is not defined"
9
43
  end
10
44
  end
11
45
  end
@@ -6,5 +6,9 @@ module Adrian
6
6
  @value = value
7
7
  @created_at = created_at
8
8
  end
9
+
10
+ def age
11
+ Time.now - created_at
12
+ end
9
13
  end
10
14
  end
@@ -1,3 +1,3 @@
1
1
  module Adrian
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -3,7 +3,7 @@ require_relative 'test_helper'
3
3
  describe Adrian::Dispatcher do
4
4
  before do
5
5
  $done_items = []
6
- @q = Adrian::ArrayQueue.new
6
+ @q = Adrian::ArrayQueue.new([], :max_age => 1000)
7
7
  @dispatcher = Adrian::Dispatcher.new(:stop_when_done => true)
8
8
  @worker = TestWorker
9
9
  end
@@ -16,7 +16,7 @@ describe Adrian::Dispatcher do
16
16
  end
17
17
 
18
18
  def perform
19
- $done_items << [@boss, @item.value]
19
+ $done_items << @item.value
20
20
  end
21
21
 
22
22
  def report_to(boss)
@@ -33,7 +33,38 @@ describe Adrian::Dispatcher do
33
33
 
34
34
  @dispatcher.start(@q, @worker)
35
35
 
36
- $done_items.must_equal([[@dispatcher, 1], [@dispatcher, 2], [@dispatcher, 3]])
36
+ $done_items.must_equal([1, 2, 3])
37
+ end
38
+ end
39
+
40
+ describe "a queue with old items" do
41
+ before do
42
+ @q.push(Adrian::QueueItem.new(1, Time.now))
43
+ @old_item = Adrian::QueueItem.new(2, Time.now - 2000)
44
+ @q.push(@old_item)
45
+ @q.push(Adrian::QueueItem.new(3, Time.now))
46
+ end
47
+
48
+ it 'skips the old items' do
49
+ @dispatcher.start(@q, @worker)
50
+
51
+ $done_items.must_equal([1, 3])
52
+ end
53
+
54
+ it 'calls the handler for Adrian::Queue::ItemTooOldError' do
55
+ handled_items = []
56
+ handled_exceptions = []
57
+
58
+ @dispatcher.on_failure(Adrian::Queue::ItemTooOldError) do |item, worker, exception|
59
+ handled_items << item
60
+ handled_exceptions << exception
61
+ end
62
+
63
+ @dispatcher.start(@q, @worker)
64
+
65
+ handled_items.must_equal [@old_item]
66
+ handled_exceptions.size.must_equal 1
67
+ handled_exceptions.first.must_be_instance_of Adrian::Queue::ItemTooOldError
37
68
  end
38
69
  end
39
70
 
@@ -0,0 +1,30 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe Adrian::Queue do
4
+ class TestQueue < Adrian::Queue
5
+ attr_accessor :item
6
+
7
+ def pop_item
8
+ @item
9
+ end
10
+
11
+ def push_item(item)
12
+ @item = item
13
+ end
14
+ end
15
+
16
+ describe 'when a max age is defined' do
17
+ before { @q = TestQueue.new(:max_age => 60) }
18
+
19
+ it 'validates the age of items' do
20
+ item = Adrian::QueueItem.new('value', Time.now)
21
+ @q.push(item)
22
+ @q.pop.must_equal item
23
+
24
+ item = Adrian::QueueItem.new('value', Time.now - 120)
25
+ @q.push(item)
26
+ lambda { @q.pop }.must_raise(Adrian::Queue::ItemTooOldError)
27
+ end
28
+ end
29
+
30
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adrian
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-10-22 00:00:00.000000000 Z
13
+ date: 2012-10-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
@@ -105,6 +105,7 @@ files:
105
105
  - test/file_item_test.rb
106
106
  - test/filters_test.rb
107
107
  - test/girl_friday_dispatcher_test.rb
108
+ - test/queue_test.rb
108
109
  - test/rotating_directory_queue_test.rb
109
110
  - test/test_helper.rb
110
111
  - test/worker_test.rb
@@ -124,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
124
125
  version: '0'
125
126
  segments:
126
127
  - 0
127
- hash: -4323319423024807981
128
+ hash: -2683630190484643052
128
129
  required_rubygems_version: !ruby/object:Gem::Requirement
129
130
  none: false
130
131
  requirements:
@@ -133,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
134
  version: '0'
134
135
  segments:
135
136
  - 0
136
- hash: -4323319423024807981
137
+ hash: -2683630190484643052
137
138
  requirements: []
138
139
  rubyforge_project:
139
140
  rubygems_version: 1.8.24
@@ -150,6 +151,7 @@ test_files:
150
151
  - test/file_item_test.rb
151
152
  - test/filters_test.rb
152
153
  - test/girl_friday_dispatcher_test.rb
154
+ - test/queue_test.rb
153
155
  - test/rotating_directory_queue_test.rb
154
156
  - test/test_helper.rb
155
157
  - test/worker_test.rb