alephant 0.0.9.8-java → 0.0.9.9-java

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: 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