alephant 0.0.9.8-java → 0.0.9.9-java

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: 9431f717738595e68a8a0c3b1bcd8f66cba57233
4
- data.tar.gz: 1befa37fc85eb905ec085cdded713ce2192f1317
3
+ metadata.gz: 756986d1dd5f6db8d9dd0f75d26432af435bc915
4
+ data.tar.gz: 05a8a13c5c52efd12ae21744bbd2dd9aa1cc1f93
5
5
  SHA512:
6
- metadata.gz: 2c7f72b93b915b929ffc5aaae66326d89e7cafbdf6f0ce48348ba5d7b8d1276d7e8448e87deb0d97dc5edcb7994136aa7a5d4c8c352d9729e4b44ef26d04e502
7
- data.tar.gz: c8ac8b48eb497dad1d0b43eee8daec450a800ca87367c509abb5b502f3c6f7d8a4a2c2667f6b1647deb798f57f34fca52d3d62b53355463658c2c36675ebd7a1
6
+ metadata.gz: 53dbcfce2dfc411d514a519f1ef805aeccbb4cd8ec97f72c5c79b05a95872932779b7699dd208c0a5234c20747895d858dab3c74388a4b1a048088dd98e81a36
7
+ data.tar.gz: 8edf5c153d6da5691657ca275ce3b2b6e4960641be4e9e731edea571a60f88fd267b9dc25ef3e076930229eb414ed80b0e4ad391c474e31475b3411ac20284a0
data/lib/alephant.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'aws-sdk'
2
-
3
1
  require_relative 'env'
4
2
 
5
3
  require 'alephant/models/logger'
@@ -7,6 +5,7 @@ require 'alephant/models/queue'
7
5
  require 'alephant/models/cache'
8
6
  require 'alephant/models/renderer'
9
7
  require 'alephant/models/multi_renderer'
8
+ require 'alephant/models/sequence_table'
10
9
  require 'alephant/models/sequencer'
11
10
  require 'alephant/models/parser'
12
11
 
@@ -33,13 +32,7 @@ module Alephant
33
32
  set_opts(opts)
34
33
 
35
34
  @logger = ::Alephant.logger
36
- @sequencer = Sequencer.new(
37
- {
38
- :table_name => @table_name
39
- },
40
- @sqs_queue_id
41
- )
42
-
35
+ @sequencer = Sequencer.create(@table_name, @sqs_queue_id, @sequence_id)
43
36
  @queue = Queue.new(@sqs_queue_id)
44
37
  @cache = Cache.new(@s3_bucket_id, @s3_object_path)
45
38
  @multi_renderer = MultiRenderer.new(@component_id, @view_path)
@@ -59,9 +52,9 @@ module Alephant
59
52
  def receive(msg)
60
53
  @logger.info("Alephant.receive: with id #{msg.id} and body digest: #{msg.md5}")
61
54
 
62
- if @sequencer.sequential?(msg, @sequence_id)
55
+ if @sequencer.sequential?(msg)
63
56
  write @parser.parse msg.body
64
- @sequencer.set_last_seen(msg, @sequence_id)
57
+ @sequencer.set_last_seen(msg)
65
58
  else
66
59
  @logger.warn("Alephant.receive: out of sequence message received #{msg.id} (discarded)")
67
60
  end
@@ -0,0 +1,99 @@
1
+ require 'aws-sdk'
2
+ require 'thread'
3
+ require 'timeout'
4
+
5
+ module Alephant
6
+ module Sequencer
7
+ class SequenceTable
8
+ attr_reader :table_name
9
+
10
+ TIMEOUT = 120
11
+ DEFAULT_CONFIG = {
12
+ :write_units => 5,
13
+ :read_units => 10,
14
+ }
15
+ SCHEMA = {
16
+ :hash_key => {
17
+ :key => :string,
18
+ :value => :string
19
+ }
20
+ }
21
+
22
+ def initialize(table_name, config = DEFAULT_CONFIG)
23
+ @mutex = Mutex.new
24
+ @dynamo_db = AWS::DynamoDB.new
25
+ @table_name = table_name
26
+ @config = config
27
+ end
28
+
29
+ def create
30
+ @mutex.synchronize do
31
+ ensure_table_exists
32
+ ensure_table_active
33
+ end
34
+ end
35
+
36
+ def table
37
+ @table ||= @dynamo_db.tables[@table_name]
38
+ end
39
+
40
+ def sequence_for(ident)
41
+ rows = batch_get_value_for(ident)
42
+ rows.count >= 1 ? rows.first['value'].to_i : 0
43
+ end
44
+
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]
51
+ )
52
+ }.process!
53
+ end
54
+ end
55
+
56
+ def delete_item!(ident)
57
+ table.items[ident].delete
58
+ end
59
+
60
+ private
61
+ def batch_get_value_for(ident)
62
+ table.batch_get(['value'],[ident],batch_get_opts)
63
+ end
64
+
65
+ def batch_get_opts
66
+ { :consistent_read => true }
67
+ end
68
+
69
+ def ensure_table_exists
70
+ create_dynamodb_table unless table.exists?
71
+ end
72
+
73
+ def ensure_table_active
74
+ sleep_until_table_active unless table_active?
75
+ end
76
+
77
+ def create_dynamodb_table
78
+ @table = @dynamo_db.tables.create(
79
+ @table_name,
80
+ @config[:read_units],
81
+ @config[:write_units],
82
+ SCHEMA
83
+ )
84
+ end
85
+
86
+ def table_active?
87
+ table.status == :active
88
+ end
89
+
90
+ def sleep_until_table_active
91
+ begin
92
+ Timeout::timeout(TIMEOUT) do
93
+ sleep 1 until table_active?
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,91 +1,61 @@
1
- require 'aws-sdk'
2
1
  require 'jsonpath'
3
2
 
4
3
  module Alephant
5
- class Sequencer
6
- attr_reader :id, :table_name, :table_conf
4
+ module Sequencer
5
+ @@sequence_tables = {}
7
6
 
8
- def table_conf_defaults
9
- {
10
- :write_units => 5,
11
- :read_units => 10,
12
- :schema => {
13
- :hash_key => {
14
- :key => :string,
15
- :value => :string
16
- }
17
- }
18
- }
7
+ def self.create(table_name, ident, jsonpath = nil)
8
+ @@sequence_tables[table_name] ||= SequenceTable.new(table_name)
9
+ Sequencer.new(@@sequence_tables[table_name], ident, jsonpath)
19
10
  end
20
11
 
21
- def initialize(opts, id)
22
- @logger = ::Alephant.logger
12
+ class Sequencer
13
+ attr_reader :ident, :jsonpath
23
14
 
24
- dynamo_db = AWS::DynamoDB.new
15
+ def initialize(sequence_table, id, sequence_path = nil)
16
+ @mutex = Mutex.new
17
+ @sequence_table = sequence_table
18
+ @jsonpath = sequence_path
19
+ @ident = id
25
20
 
26
- @id = id
27
- @table_name = opts[:table_name]
28
- @table_conf = opts[:table_conf] || table_conf_defaults
29
- @table = dynamo_db.tables[@table_name]
30
-
31
- begin
32
- sleep_until_table_active
33
- rescue AWS::DynamoDB::Errors::ResourceNotFoundException
34
- @logger.error("Sequencer.initialize: DynamoDB resource was not found.")
35
-
36
- @table = dynamo_db.tables.create(
37
- @table_name,
38
- @table_conf[:read_units],
39
- @table_conf[:write_units],
40
- @table_conf[:schema]
41
- )
21
+ ::Alephant.logger.info("Sequencer.initialize: with id #{@ident}")
22
+ @sequence_table.create
23
+ end
42
24
 
43
- @logger.info("Sequencer.initialize: Creating table with name #{@table_name}, read units #{@table_conf[:read_units]}, write units #{@table_conf[:write_units]}, schema #{@table_conf[:schema]}")
25
+ def sequential?(data)
26
+ get_last_seen < sequence_id_from(data)
27
+ end
44
28
 
45
- sleep_until_table_active
29
+ def delete!
30
+ @sequence_table.delete_item!(ident)
46
31
  end
47
32
 
48
- @logger.info("Sequencer.initialize: end with id #{@id}")
49
- end
33
+ def set_last_seen(data)
34
+ last_seen_id = sequence_id_from(data)
50
35
 
51
- def sequential?(data, jsonpath = nil)
52
- get_last_seen < get_sequence_id_from(data, jsonpath)
53
- end
36
+ @sequence_table.set_sequence_for(ident, last_seen_id)
37
+ ::Alephant.logger.info("Sequencer.set_last_seen: #{ident}:#{last_seen_id}")
38
+ end
54
39
 
55
- def set_last_seen(data, jsonpath)
56
- last_seen_id = get_sequence_id_from(data, jsonpath)
40
+ def get_last_seen
41
+ @sequence_table.sequence_for(ident)
42
+ end
57
43
 
58
- batch = AWS::DynamoDB::BatchWrite.new
59
- batch.put(@table_name, [:key => @id,:value => last_seen_id])
60
- batch.process!
61
- @logger.info("Sequencer.set_last_seen: id #{id} and last_seen_id #{last_seen_id}")
62
- end
44
+ private
45
+ def sequence_id_from(data)
46
+ jsonpath.nil? ?
47
+ default_sequence_id_for(data) :
48
+ sequence_from_jsonpath_for(data)
49
+ end
63
50
 
64
- def get_sequence_id_from(data, jsonpath)
65
- jsonpath.nil? ?
66
- data.body['sequence_id'].to_i :
51
+ def sequence_from_jsonpath_for(data)
67
52
  JsonPath.on(data.body, jsonpath).first
68
- end
53
+ end
69
54
 
70
- def get_last_seen
71
- begin
72
- @table.batch_get(
73
- ['value'],
74
- [@id],
75
- {
76
- :consistent_read => true
77
- }
78
- ).first["value"].to_i
79
- rescue Exception => e
80
- trace = e.backtrace.join('\n')
81
- @logger.error("Sequencer.get_last_seen: id #{id}\nmessage: #{e.message}\ntrace: #{trace}")
82
- 0
55
+ def default_sequence_id_for(data)
56
+ data.body['sequence_id'].to_i
83
57
  end
84
- end
85
58
 
86
- def sleep_until_table_active
87
- sleep 1 until @table.status == :active
88
59
  end
89
-
90
60
  end
91
61
  end
@@ -1,3 +1,3 @@
1
1
  module Alephant
2
- VERSION = "0.0.9.8"
2
+ VERSION = "0.0.9.9"
3
3
  end
data/lib/env.rb CHANGED
@@ -1,3 +1,5 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+
1
3
  require 'aws-sdk'
2
4
  require 'yaml'
3
5
 
@@ -10,7 +10,7 @@ describe Alephant::Alephant do
10
10
  cache = double()
11
11
  multi_renderer = double()
12
12
 
13
- Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
13
+ Alephant::Sequencer.stub(:create).and_return(sequencer)
14
14
  Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
15
15
  Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
16
16
  Alephant::MultiRenderer.any_instance.stub(:initialize).and_return(multi_renderer)
@@ -49,14 +49,15 @@ describe Alephant::Alephant do
49
49
  end
50
50
 
51
51
  context "initializes @sequencer" do
52
- it "with Sequencer.new({ :table_name => :table_name }, @sqs_queue_id)" do
52
+ it "with Sequencer.create(:table_name, @sqs_queue_id)" do
53
53
  Alephant::Sequencer
54
- .should_receive(:new)
55
- .with({ :table_name => :table_name }, :sqs_queue_id)
54
+ .should_receive(:create)
55
+ .with(:table_name, :sqs_queue_id, :sequence_id)
56
56
 
57
57
  instance = subject.new({
58
58
  :table_name => :table_name,
59
- :sqs_queue_id => :sqs_queue_id
59
+ :sqs_queue_id => :sqs_queue_id,
60
+ :sequence_id => :sequence_id
60
61
  })
61
62
  end
62
63
  end
@@ -107,7 +108,7 @@ describe Alephant::Alephant do
107
108
  cache = double()
108
109
  multi_renderer = double()
109
110
 
110
- Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
111
+ Alephant::Sequencer.stub(:create).and_return(sequencer)
111
112
  Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
112
113
  Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
113
114
  Alephant::MultiRenderer.any_instance.stub(:initialize).and_return(multi_renderer)
@@ -144,22 +145,11 @@ describe Alephant::Alephant do
144
145
  cache = double()
145
146
  multi_renderer = double()
146
147
 
147
- Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
148
148
  Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
149
149
  Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
150
150
  Alephant::MultiRenderer.any_instance.stub(:initialize).and_return(multi_renderer)
151
151
  end
152
152
 
153
- it "takes json as an argument" do
154
- instance = subject.new
155
-
156
- msg = double()
157
- msg.stub(:body).and_return('notjson')
158
-
159
- expect { JsonPath.on(msg.body, '$.foo') }
160
- .to raise_error(MultiJson::LoadError);
161
- end
162
-
163
153
  it "writes data to cache if sequential order is true" do
164
154
  data = "{ \"foo\":\"bar\" }"
165
155
 
@@ -168,17 +158,22 @@ describe Alephant::Alephant do
168
158
  msg.stub(:md5).and_return(:md5)
169
159
  msg.stub(:body).and_return(data)
170
160
 
171
- instance = subject.new
172
161
 
173
- Alephant::Sequencer
162
+ Alephant::Sequencer::Sequencer
174
163
  .any_instance
175
164
  .stub(:sequential?)
176
165
  .and_return(true)
177
166
 
178
- Alephant::Sequencer
167
+ Alephant::Sequencer::SequenceTable
168
+ .any_instance
169
+ .stub(:create)
170
+
171
+ Alephant::Sequencer::Sequencer
179
172
  .any_instance
180
173
  .stub(:set_last_seen)
181
174
 
175
+ instance = subject.new
176
+
182
177
  instance
183
178
  .should_receive(:write)
184
179
  .with(JSON.parse(data, :symbolize_names => true))
@@ -192,7 +187,7 @@ describe Alephant::Alephant do
192
187
  sequencer = double()
193
188
  queue = double()
194
189
 
195
- Alephant::Sequencer
190
+ Alephant::Sequencer::Sequencer
196
191
  .any_instance
197
192
  .stub(:initialize)
198
193
  .and_return(sequencer)
data/spec/logger_spec.rb CHANGED
@@ -7,7 +7,7 @@ describe Alephant::LogSystem do
7
7
  cache = double()
8
8
  renderer = double()
9
9
 
10
- Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
10
+ Alephant::Sequencer.stub(:create).and_return(sequencer)
11
11
  Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
12
12
  Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
13
13
  Alephant::Renderer.any_instance.stub(:initialize).and_return(renderer)
@@ -1,124 +1,107 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Alephant::Sequencer do
4
- subject { Alephant::Sequencer }
5
3
 
6
- describe "initialize(opts, id)" do
4
+ describe Alephant::Sequencer do
5
+ let(:ident) { :ident }
6
+ let(:jsonpath) { :jsonpath }
7
7
 
8
- it "sets @id, @table_name and @table_conf" do
9
- AWS::DynamoDB.any_instance.stub(:initialize).and_return({
10
- :tables => {
11
- :status => :active
12
- }
13
- })
8
+ describe ".create(table_name, ident, jsonpath)" do
9
+ it "should return a Sequencer" do
10
+ Alephant::Sequencer::SequenceTable.any_instance.stub(:create)
11
+ expect(subject.create(:table_name, ident, jsonpath)).to be_a Alephant::Sequencer::Sequencer
12
+ end
13
+ end
14
14
 
15
- Alephant::Sequencer.any_instance.stub(:sleep_until_table_active)
15
+ describe Alephant::Sequencer::Sequencer do
16
+ let(:data) { double() }
17
+ let(:last_seen) { 42 }
18
+ let(:sequence_table) { double().tap { |o| o.stub(:create) } }
19
+ subject { Alephant::Sequencer::Sequencer.new(sequence_table, ident, jsonpath) }
20
+
21
+ describe "#initialize(opts, id)" do
22
+ it "sets @jsonpath, @ident" do
23
+ expect(subject.jsonpath).to eq(jsonpath)
24
+ expect(subject.ident).to eq(ident)
25
+ end
16
26
 
17
- instance = subject.new({
18
- :table_name => :table_name,
19
- :table_conf => :table_conf
20
- }, :sqs_queue_id)
27
+ it "calls create on sequence_table" do
28
+ table = double()
29
+ table.should_receive(:create)
21
30
 
22
- expect(instance.id).to eq(:sqs_queue_id)
23
- expect(instance.table_name).to eq(:table_name)
24
- expect(instance.table_conf).to eq(:table_conf)
31
+ Alephant::Sequencer::Sequencer.new(table, ident, jsonpath)
32
+ end
25
33
  end
26
34
 
27
- context "sleep_until_table_active raises" do
28
- context "AWS::DynamoDB::Errors::ResourceNotFoundException" do
29
- it "dynamo_db.tables.create(@table_name, opts) then sleep_until_table_active" do
30
- opts = {
31
- :table_name => :table_name,
32
- :table_conf => {
33
- :read_units => :read_units,
34
- :write_units => :write_units,
35
- :schema => :schema
36
- }
37
- }
38
-
39
- table_collection = double()
40
- table_collection.should_receive(:create).with(
41
- opts[:table_name],
42
- opts[:table_conf][:read_units],
43
- opts[:table_conf][:write_units],
44
- opts[:table_conf][:schema]
45
- )
46
-
47
- AWS::DynamoDB.any_instance.stub(:tables).and_return({},table_collection)
48
-
49
- Alephant::Sequencer
50
- .any_instance
51
- .stub(:sleep_until_table_active).and_yield do
52
- @times_called ||= 0
53
- raise AWS::DynamoDB::Errors::ResourceNotFoundException if @times_called == 0
54
- @times_called += 1
55
- end
56
-
57
- subject.new(opts, :id)
58
- end
35
+ describe "#get_last_seen" do
36
+ it "returns sequence_table.sequence_for(ident)" do
37
+ table = double()
38
+ table.stub(:create)
39
+ table.should_receive(:sequence_for).with(ident).and_return(:expected_value)
40
+
41
+ expect(
42
+ Alephant::Sequencer::Sequencer.new(table, ident).get_last_seen
43
+ ).to eq(:expected_value)
59
44
  end
60
45
  end
61
- end
62
-
63
- describe "sequential?(data, jsonpath = nil)" do
64
- let(:jsonpath) { '$.sequence_id' }
65
- let(:instance) { subject.new }
66
- let(:id_value) { 0 }
67
- let(:data) { double() }
68
46
 
69
- before(:each) do
70
- Alephant::Sequencer
71
- .any_instance.stub(:initialize)
72
- .and_return(double())
47
+ describe "#set_last_seen(data)" do
48
+ before(:each) do
49
+ Alephant::Sequencer::Sequencer.any_instance.stub(:sequence_id_from).and_return(last_seen)
50
+ end
73
51
 
74
- Alephant::Sequencer
75
- .any_instance
76
- .stub(:get_last_seen)
77
- .and_return(1)
52
+ it "calls set_sequence_for(ident, last_seen)" do
53
+ table = double()
54
+ table.stub(:create)
55
+ table.should_receive(:set_sequence_for).with(ident, last_seen)
78
56
 
79
- data.stub(:body).and_return('sequence_id' => id_value)
57
+ Alephant::Sequencer::Sequencer.new(table, ident).set_last_seen(data)
58
+ end
80
59
  end
81
60
 
82
- context "jsonpath provided" do
83
- context "in sequence" do
84
- let(:id_value) { 2 }
61
+ describe "#sequential?(data, jsonpath)" do
85
62
 
86
- it "looks up data using jsonpath (returns true)" do
87
- in_sequence = instance.sequential?(data, jsonpath)
88
- expect(in_sequence).to eq(true)
89
- end
63
+ before(:each) do
64
+ Alephant::Sequencer::Sequencer.any_instance.stub(:get_last_seen).and_return(1)
65
+ data.stub(:body).and_return('sequence_id' => id_value)
90
66
  end
91
67
 
92
- context "out of sequence" do
93
- let(:id_value) { 0 }
68
+ context "jsonpath = '$.sequence_id'" do
69
+ let(:jsonpath) { '$.sequence_id' }
70
+ subject { Alephant::Sequencer::Sequencer.new(sequence_table, :ident, jsonpath) }
71
+ context "sequential" do
72
+ let(:id_value) { 2 }
73
+ it "is true" do
74
+ expect(subject.sequential?(data)).to be_true
75
+ end
76
+ end
94
77
 
95
- it "looks up data using jsonpath (returns false)" do
96
- in_sequence = instance.sequential?(data, jsonpath)
97
- expect(in_sequence).to eq(false)
78
+ context "nonsequential" do
79
+ let(:id_value) { 0 }
80
+ it "is false" do
81
+ expect(subject.sequential?(data)).to be_false
82
+ end
98
83
  end
99
84
  end
100
- end
101
85
 
102
- context "jsonpath NOT provided" do
103
- context "in sequence" do
104
- let(:id_value) { 2 }
86
+ context "jsonpath = nil" do
87
+ let(:jsonpath) { nil }
88
+ subject { Alephant::Sequencer::Sequencer.new(sequence_table, :ident, jsonpath) }
105
89
 
106
- it "looks up data using a fallback key (returns true)" do
107
- in_sequence = instance.sequential?(data)
108
- expect(in_sequence).to eq(true)
90
+ context "sequential" do
91
+ let(:id_value) { 2 }
92
+ it "is true" do
93
+ expect(subject.sequential?(data)).to be_true
94
+ end
109
95
  end
110
- end
111
-
112
- context "out of sequence" do
113
- let(:id_value) { 0 }
114
96
 
115
- it "looks up data using a fallback key (returns false)" do
116
- in_sequence = instance.sequential?(data)
117
- expect(in_sequence).to eq(false)
97
+ context "nonsequential" do
98
+ let(:id_value) { 0 }
99
+ it "is false" do
100
+ expect(subject.sequential?(data)).to be_false
101
+ end
118
102
  end
119
103
  end
120
- end
121
104
 
105
+ end
122
106
  end
123
107
  end
124
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alephant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9.8
4
+ version: 0.0.9.9
5
5
  platform: java
6
6
  authors:
7
7
  - Robert Kenny
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-10 00:00:00.000000000 Z
11
+ date: 2014-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -234,6 +234,7 @@ files:
234
234
  - lib/alephant/models/parser.rb
235
235
  - lib/alephant/models/queue.rb
236
236
  - lib/alephant/models/renderer.rb
237
+ - lib/alephant/models/sequence_table.rb
237
238
  - lib/alephant/models/sequencer.rb
238
239
  - lib/alephant/preview/server.rb
239
240
  - lib/alephant/preview/template.rb