adrian 1.2.0 → 1.3.0

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.
@@ -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