alephant-sequencer 0.0.4 → 0.0.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: c9469dfac1eb96f8c9386bf691836cf8f3017f59
4
- data.tar.gz: c97554d0a0b758413c9024f4ee4d2fd5f9167faf
3
+ metadata.gz: f3a700631c4ac5a7dcbb393c5b646c94ff570507
4
+ data.tar.gz: 231923e71aa7e8f0d4af03e5f3088b14d8c365d1
5
5
  SHA512:
6
- metadata.gz: 10ef0ab3836211d83e502690620f7d38b10c44761dd99abe9b43f47eca517de9908b54b971c3287ffecef54ef9b693c03837489e6a422e427d74d86d5c16b0c4
7
- data.tar.gz: be84f7081d5ab556ee69fe5fd96d6adb5db862e69ca6ea5b387db3b9915f812bde4df8e9dc5cf6c11fc96e1a2cbf6bb09f83fbe2c39ca4430b87525c525737f4
6
+ metadata.gz: 6ee44b240e0007b839b23069601ace6a2221991f12ca560cdc6ca6c372c9ab20db526f7545a06a56ff337a433fe6fd44cce7b3c8d1a91a03ca26d1e9513104bf
7
+ data.tar.gz: a34a2e07fe1b5184ca238a385e29dbbc17a90bc99de6251bffd7a37952500e6549bbe3c1431dc3e153d1fedb2f6bf356ce23d335720d2df674845d96e6daa971
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/.+\.rb$})
4
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
5
+ watch('spec/spec_helper.rb') { "spec" }
6
+ end
@@ -2,9 +2,13 @@ require 'aws-sdk'
2
2
  require 'thread'
3
3
  require 'timeout'
4
4
 
5
+ require 'alephant/logger'
6
+
5
7
  module Alephant
6
8
  module Sequencer
7
9
  class SequenceTable
10
+ include ::Alephant::Logger
11
+
8
12
  attr_reader :table_name
9
13
 
10
14
  TIMEOUT = 120
@@ -37,19 +41,25 @@ module Alephant
37
41
  @table ||= @dynamo_db.tables[@table_name]
38
42
  end
39
43
 
44
+ def sequence_exists(ident)
45
+ !(table.items.where(:key => ident) == 0)
46
+ end
47
+
40
48
  def sequence_for(ident)
41
49
  rows = batch_get_value_for(ident)
42
- rows.count >= 1 ? rows.first['value'].to_i : 0
50
+ rows.count >= 1 ? rows.first['value'].to_i : nil
43
51
  end
44
52
 
45
- def set_sequence_for(ident,value)
46
- @mutex.synchronize do
47
- AWS::DynamoDB::BatchWrite.new.tap { |batch|
48
- batch.put(
49
- table_name,
50
- [:key => ident,:value => value]
53
+ def set_sequence_for(ident, value, last_seen_check = nil)
54
+ begin
55
+ @mutex.synchronize do
56
+ table.items.put(
57
+ {:key => ident, :value => value },
58
+ put_condition(last_seen_check)
51
59
  )
52
- }.process!
60
+ end
61
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException => e
62
+ logger.warn("SequenceTable#set_sequence_for: #{e.message}")
53
63
  end
54
64
  end
55
65
 
@@ -58,10 +68,22 @@ module Alephant
58
68
  end
59
69
 
60
70
  private
71
+ def put_condition(last_seen_check)
72
+ last_seen_check.nil? ? unless_exists(:key) : if_value(last_seen_check)
73
+ end
74
+
61
75
  def batch_get_value_for(ident)
62
76
  table.batch_get(['value'],[ident],batch_get_opts)
63
77
  end
64
78
 
79
+ def unless_exists(key)
80
+ { :unless_exists => key }
81
+ end
82
+
83
+ def if_value(value)
84
+ { :if => { :value => value.to_i } }
85
+ end
86
+
65
87
  def batch_get_opts
66
88
  { :consistent_read => true }
67
89
  end
@@ -1,4 +1,5 @@
1
1
  require 'jsonpath'
2
+
2
3
  require 'alephant/logger'
3
4
 
4
5
  module Alephant
@@ -8,28 +9,45 @@ module Alephant
8
9
  attr_reader :ident, :jsonpath
9
10
 
10
11
  def initialize(sequence_table, id, sequence_path)
11
- @mutex = Mutex.new
12
12
  @sequence_table = sequence_table
13
+ @sequence_table.create
14
+
15
+ @exists = exists?
13
16
  @jsonpath = sequence_path
14
17
  @ident = id
15
-
16
- @sequence_table.create
17
18
  end
18
19
 
19
20
  def sequential?(msg)
20
- get_last_seen < sequence_id_from(msg)
21
+ (get_last_seen || 0) < sequence_id_from(msg)
22
+ end
23
+
24
+ def exists?
25
+ @exists || @sequence_table.sequence_exists(ident)
26
+ end
27
+
28
+ def sequence(msg, &block)
29
+ last_seen_id = get_last_seen
30
+ block.call(msg)
31
+
32
+ if sequential?(msg)
33
+ set_last_seen(msg, last_seen_id)
34
+ end
21
35
  end
22
36
 
23
37
  def delete!
24
- logger.info("Sequencer.delete!: #{ident}")
38
+ logger.info("Sequencer#delete!: #{ident}")
39
+ @exists = false
25
40
  @sequence_table.delete_item!(ident)
26
41
  end
27
42
 
28
- def set_last_seen(msg)
29
- last_seen_id = sequence_id_from(msg)
30
- logger.info("Sequencer.set_last_seen: #{last_seen_id}")
43
+ def set_last_seen(msg, last_seen_check = nil)
44
+ seen_id = sequence_id_from(msg)
45
+ logger.info("Sequencer#set_last_seen: #{seen_id}")
31
46
 
32
- @sequence_table.set_sequence_for(ident, last_seen_id)
47
+ @sequence_table.set_sequence_for(
48
+ ident, seen_id,
49
+ (exists? ? last_seen_check : nil)
50
+ )
33
51
  end
34
52
 
35
53
  def get_last_seen
@@ -37,7 +55,7 @@ module Alephant
37
55
  end
38
56
 
39
57
  def sequence_id_from(msg)
40
- JsonPath.on(msg.body, jsonpath).first
58
+ JsonPath.on(msg.body, jsonpath).first.to_i
41
59
  end
42
60
  end
43
61
  end
@@ -1,5 +1,5 @@
1
1
  module Alephant
2
2
  module Sequencer
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -14,17 +14,28 @@ describe Alephant::Sequencer do
14
14
  describe Alephant::Sequencer::Sequencer do
15
15
  let(:data) { double() }
16
16
  let(:last_seen) { 42 }
17
- let(:sequence_table) { double().tap { |o| o.stub(:create) } }
18
- subject { Alephant::Sequencer::Sequencer.new(sequence_table, ident, jsonpath) }
17
+
18
+ def sequence_table
19
+ table = double()
20
+ table.stub(:create)
21
+ table.stub(:sequence_exists)
22
+ table.stub(:sequence_for)
23
+ table.stub(:set_sequence_for)
24
+
25
+ table
26
+ end
19
27
 
20
28
  describe "#initialize(opts, id)" do
21
29
  it "sets @jsonpath, @ident" do
30
+ subject = Alephant::Sequencer::Sequencer.new(sequence_table, ident, jsonpath)
31
+
22
32
  expect(subject.jsonpath).to eq(jsonpath)
23
33
  expect(subject.ident).to eq(ident)
24
34
  end
25
35
 
26
36
  it "calls create on sequence_table" do
27
37
  table = double()
38
+ table.stub(:sequence_exists)
28
39
  table.should_receive(:create)
29
40
 
30
41
  Alephant::Sequencer::Sequencer.new(table, ident, jsonpath)
@@ -34,6 +45,7 @@ describe Alephant::Sequencer do
34
45
  describe "#get_last_seen" do
35
46
  it "returns sequence_table.sequence_for(ident)" do
36
47
  table = double()
48
+ table.stub(:sequence_exists)
37
49
  table.stub(:create)
38
50
  table.should_receive(:sequence_for).with(ident).and_return(:expected_value)
39
51
 
@@ -50,8 +62,10 @@ describe Alephant::Sequencer do
50
62
 
51
63
  it "calls set_sequence_for(ident, last_seen)" do
52
64
  table = double()
65
+ table.stub(:sequence_exists)
53
66
  table.stub(:create)
54
- table.should_receive(:set_sequence_for).with(ident, last_seen)
67
+ table.stub(:sequence_for)
68
+ table.should_receive(:set_sequence_for).with(ident, last_seen, nil)
55
69
 
56
70
  Alephant::Sequencer::Sequencer.new(table, ident, jsonpath).set_last_seen(data)
57
71
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alephant-sequencer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Kenny
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-17 00:00:00.000000000 Z
11
+ date: 2014-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -188,6 +188,7 @@ files:
188
188
  - .gitignore
189
189
  - .travis.yml
190
190
  - Gemfile
191
+ - Guardfile
191
192
  - LICENSE.txt
192
193
  - README.md
193
194
  - Rakefile