alephant-lookup 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/alephant-lookup.gemspec +4 -3
- data/lib/alephant/lookup.rb +2 -2
- data/lib/alephant/lookup/lookup_cache.rb +69 -0
- data/lib/alephant/lookup/lookup_helper.rb +28 -12
- data/lib/alephant/lookup/version.rb +1 -1
- data/spec/lookup_spec.rb +60 -38
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f7e07c301d41b1ad0433b62cbd83e89d4e1a911
|
4
|
+
data.tar.gz: 785873a081b3d684b092f4aa74d408f22dab9141
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 540b154e9875cb1c1977ac87f68c00dbb0b394f2e36f8d3e73703f3f29605e0a1b63ba9f9fbe275804c2e9a094038303d0eea936d0aa8fc3a096c9d39e952010
|
7
|
+
data.tar.gz: 992e6df834993e052f6f82ac1cc279a8e774569e4ee6a59c58b6e06fd46c49132c31b3d83bc3fae9e6563e0a01d493d180d6ab378a2a0475448db4238d9da780
|
data/alephant-lookup.gemspec
CHANGED
@@ -28,9 +28,10 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency "bundler", "~> 1.5"
|
29
29
|
spec.add_development_dependency "rake"
|
30
30
|
|
31
|
-
spec.add_runtime_dependency
|
32
|
-
spec.add_runtime_dependency
|
33
|
-
spec.add_runtime_dependency
|
31
|
+
spec.add_runtime_dependency "aws-sdk", "~> 1.0"
|
32
|
+
spec.add_runtime_dependency "alephant-logger"
|
33
|
+
spec.add_runtime_dependency "alephant-support"
|
34
34
|
|
35
|
+
spec.add_runtime_dependency "dalli-elasticache"
|
35
36
|
spec.add_runtime_dependency "crimp"
|
36
37
|
end
|
data/lib/alephant/lookup.rb
CHANGED
@@ -9,9 +9,9 @@ module Alephant
|
|
9
9
|
include Logger
|
10
10
|
@@lookup_tables = {}
|
11
11
|
|
12
|
-
def self.create(table_name)
|
12
|
+
def self.create(table_name, config={})
|
13
13
|
@@lookup_tables[table_name] ||= LookupTable.new(table_name)
|
14
|
-
LookupHelper.new(@@lookup_tables[table_name])
|
14
|
+
LookupHelper.new(@@lookup_tables[table_name], config)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'dalli-elasticache'
|
2
|
+
require 'alephant/logger'
|
3
|
+
|
4
|
+
module Alephant
|
5
|
+
module Lookup
|
6
|
+
class LookupCache
|
7
|
+
include Logger
|
8
|
+
|
9
|
+
attr_reader :config
|
10
|
+
|
11
|
+
DEFAULT_TTL = 5
|
12
|
+
|
13
|
+
def initialize(config={})
|
14
|
+
@config = config
|
15
|
+
|
16
|
+
unless config_endpoint.nil?
|
17
|
+
@elasticache ||= ::Dalli::ElastiCache.new(config_endpoint, { :expires_in => ttl })
|
18
|
+
@client ||= @elasticache.client
|
19
|
+
else
|
20
|
+
logger.debug "Alephant::LookupCache::#initialize: No config endpoint, NullClient used"
|
21
|
+
logger.metric "NoConfigEndpoint"
|
22
|
+
@client = NullClient.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(key, &block)
|
27
|
+
begin
|
28
|
+
versioned_key = versioned key
|
29
|
+
result = @client.get versioned_key
|
30
|
+
logger.info "Alephant::LookupCache#get key: #{versioned_key} - #{result ? 'hit' : 'miss'}"
|
31
|
+
logger.metric "GetKeyMiss" unless result
|
32
|
+
result ? result : set(key, block.call)
|
33
|
+
rescue StandardError => e
|
34
|
+
block.call if block_given?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def set(key, value, ttl = nil)
|
39
|
+
value.tap { |o| @client.set(versioned(key), o, ttl) }
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def config_endpoint
|
45
|
+
config["elasticache_config_endpoint"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def ttl
|
49
|
+
config['elasticache_ttl'] || DEFAULT_TTL
|
50
|
+
end
|
51
|
+
|
52
|
+
def versioned(key)
|
53
|
+
[key, cache_version].compact.join('_')
|
54
|
+
end
|
55
|
+
|
56
|
+
def cache_version
|
57
|
+
config['elasticache_cache_version']
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class NullClient
|
62
|
+
def get(key); end
|
63
|
+
|
64
|
+
def set(key, value, ttl = nil)
|
65
|
+
value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "alephant/lookup/lookup_table"
|
2
2
|
require "alephant/lookup/lookup_query"
|
3
|
+
require "alephant/lookup/lookup_cache"
|
3
4
|
|
4
5
|
require 'alephant/logger'
|
5
6
|
|
@@ -8,10 +9,11 @@ module Alephant
|
|
8
9
|
class LookupHelper
|
9
10
|
include Logger
|
10
11
|
|
11
|
-
attr_reader :lookup_table
|
12
|
+
attr_reader :lookup_table, :config
|
12
13
|
|
13
|
-
def initialize(lookup_table)
|
14
|
+
def initialize(lookup_table, config={})
|
14
15
|
@lookup_table = lookup_table
|
16
|
+
@config = config
|
15
17
|
|
16
18
|
logger.info(
|
17
19
|
"event" => "LookupHelperInitialized",
|
@@ -21,15 +23,17 @@ module Alephant
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def read(id, opts, batch_version)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
LookupCache.new(config).get(component_cache_key(id, opts, batch_version)) do
|
27
|
+
LookupQuery.new(lookup_table.table_name, id, opts, batch_version).run!.tap do
|
28
|
+
logger.info(
|
29
|
+
"event" => "LookupQuery",
|
30
|
+
"tableName" => lookup_table.table_name,
|
31
|
+
"id" => id,
|
32
|
+
"opts" => opts,
|
33
|
+
"batchVersion" => batch_version,
|
34
|
+
"method" => "#{self.class}#read"
|
35
|
+
)
|
36
|
+
end
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
@@ -53,7 +57,19 @@ module Alephant
|
|
53
57
|
end
|
54
58
|
|
55
59
|
def truncate!
|
56
|
-
|
60
|
+
lookup_table.truncate!
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def component_cache_key(id, opts, batch_version)
|
66
|
+
template_key(batch_version).gsub("{{COMPONENT_KEY}}") do |s|
|
67
|
+
LookupLocation.new(id, opts, batch_version).component_key
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def template_key(batch_version)
|
72
|
+
"#{lookup_table.table_name}/{{COMPONENT_KEY}}/#{batch_version}"
|
57
73
|
end
|
58
74
|
end
|
59
75
|
end
|
data/spec/lookup_spec.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Alephant::Lookup do
|
4
|
-
describe ".create
|
4
|
+
describe ".create" do
|
5
5
|
it "returns a lookup" do
|
6
|
-
Alephant::Lookup::LookupHelper
|
7
|
-
.any_instance
|
8
|
-
.stub(:initialize)
|
6
|
+
expect_any_instance_of(Alephant::Lookup::LookupHelper).to receive(:initialize)
|
9
7
|
|
10
8
|
expect(subject.create(:table_name)).to be_a Alephant::Lookup::LookupHelper
|
11
9
|
end
|
@@ -14,15 +12,15 @@ describe Alephant::Lookup do
|
|
14
12
|
describe Alephant::Lookup::LookupHelper do
|
15
13
|
subject { Alephant::Lookup::LookupHelper }
|
16
14
|
|
17
|
-
describe "#initialize
|
15
|
+
describe "#initialize" do
|
18
16
|
it "calls create on lookup_table" do
|
19
17
|
table = double()
|
20
|
-
table.
|
18
|
+
expect(table).to receive(:table_name)
|
21
19
|
subject.new(table)
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
|
-
describe "#read
|
23
|
+
describe "#read" do
|
26
24
|
let(:expected_query) do
|
27
25
|
{
|
28
26
|
:table_name=>"table_name",
|
@@ -32,24 +30,28 @@ describe Alephant::Lookup do
|
|
32
30
|
:key_conditions=>{
|
33
31
|
"component_key"=> {
|
34
32
|
:comparison_operator=>"EQ",
|
35
|
-
:attribute_value_list=>[{"s"=>"id/
|
33
|
+
:attribute_value_list=>[{"s"=>"id/218c835cec343537589dbf1619532e4d"}]
|
36
34
|
},
|
37
35
|
"batch_version"=>{
|
38
36
|
:comparison_operator=>"EQ",
|
39
|
-
:attribute_value_list=>[{"n"=>"
|
37
|
+
:attribute_value_list=>[{"n"=>"0"}]
|
40
38
|
}
|
41
39
|
}
|
42
40
|
}
|
43
41
|
end
|
44
42
|
|
45
|
-
it "queries DynamoDb and returns a location" do
|
46
|
-
|
47
|
-
|
48
|
-
.stub(:initialize)
|
43
|
+
it "queries DynamoDb and returns a location when not in cache" do
|
44
|
+
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
45
|
+
expect_any_instance_of(Dalli::ElastiCache).to receive(:client).and_return(Dalli::Client.new)
|
49
46
|
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
expect_any_instance_of(Dalli::Client).to receive(:get)
|
48
|
+
expect_any_instance_of(Dalli::Client).to receive(:set)
|
49
|
+
|
50
|
+
expect_any_instance_of(AWS::DynamoDB::Client::V20120810)
|
51
|
+
.to receive(:initialize)
|
52
|
+
|
53
|
+
expect_any_instance_of(AWS::DynamoDB::Client::V20120810)
|
54
|
+
.to receive(:query)
|
53
55
|
.with(expected_query)
|
54
56
|
.and_return(
|
55
57
|
{
|
@@ -61,40 +63,61 @@ describe Alephant::Lookup do
|
|
61
63
|
)
|
62
64
|
|
63
65
|
table = double().as_null_object
|
64
|
-
table.
|
66
|
+
expect(table).to receive(:table_name).and_return("table_name").exactly(4).times
|
67
|
+
|
68
|
+
config = { "elasticache_config_endpoint" => "/cache" }
|
65
69
|
|
66
|
-
instance = subject.new(table)
|
67
|
-
lookup = instance.read("id",
|
70
|
+
instance = subject.new(table, config)
|
71
|
+
lookup = instance.read("id", {:variant => "foo"}, 0)
|
68
72
|
|
69
73
|
expect(lookup.location).to eq("/location")
|
70
74
|
end
|
71
|
-
end
|
72
75
|
|
73
|
-
|
74
|
-
|
76
|
+
it "reads location from the cache when in cache" do
|
77
|
+
lookup_location = Alephant::Lookup::LookupLocation.new("id", {:variant => "foo"}, 0, "/location")
|
75
78
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
)
|
79
|
+
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
80
|
+
expect_any_instance_of(Dalli::ElastiCache).to receive(:client).and_return(Dalli::Client.new)
|
81
|
+
|
82
|
+
expect_any_instance_of(Dalli::Client).to receive(:get)
|
83
|
+
.with("table_name/id/218c835cec343537589dbf1619532e4d/0")
|
84
|
+
.and_return(lookup_location)
|
85
|
+
expect_any_instance_of(Dalli::Client).to_not receive(:set)
|
86
|
+
|
87
|
+
expect_any_instance_of(AWS::DynamoDB::Client::V20120810).to_not receive(:initialize)
|
82
88
|
|
89
|
+
expect_any_instance_of(AWS::DynamoDB::Client::V20120810).to_not receive(:query)
|
90
|
+
|
91
|
+
table = double().as_null_object
|
92
|
+
expect(table).to receive(:table_name).and_return("table_name").twice
|
93
|
+
|
94
|
+
config = { "elasticache_config_endpoint" => "/cache" }
|
95
|
+
|
96
|
+
instance = subject.new(table, config)
|
97
|
+
lookup = instance.read("id", {:variant => "foo"}, 0)
|
98
|
+
|
99
|
+
expect(lookup.location).to eq("/location")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#write" do
|
104
|
+
it "does not fail" do
|
83
105
|
lookup_table = double().as_null_object
|
84
|
-
|
85
|
-
|
106
|
+
|
107
|
+
expect(lookup_table)
|
108
|
+
.to receive(:table_name)
|
86
109
|
.and_return('test')
|
87
|
-
|
88
|
-
|
110
|
+
|
111
|
+
expect(lookup_table)
|
112
|
+
.to receive(:write)
|
89
113
|
.with(
|
90
114
|
"id/7e0c33c476b1089500d5f172102ec03e",
|
91
115
|
"0",
|
92
116
|
"/location"
|
93
117
|
)
|
94
118
|
|
95
|
-
Alephant::Lookup::LookupHelper
|
96
|
-
.
|
97
|
-
.stub(:lookup_table)
|
119
|
+
expect_any_instance_of(Alephant::Lookup::LookupHelper)
|
120
|
+
.to receive(:lookup_table)
|
98
121
|
.and_return(lookup_table)
|
99
122
|
|
100
123
|
instance = subject.new(lookup_table)
|
@@ -105,9 +128,8 @@ describe Alephant::Lookup do
|
|
105
128
|
describe "#truncate!" do
|
106
129
|
it "deletes all table rows" do
|
107
130
|
table = double()
|
108
|
-
table.
|
109
|
-
table.
|
110
|
-
table.should_receive(:truncate!)
|
131
|
+
expect(table).to receive(:table_name)
|
132
|
+
expect(table).to receive(:truncate!)
|
111
133
|
|
112
134
|
subject = Alephant::Lookup::LookupHelper.new(table)
|
113
135
|
subject.truncate!
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alephant-lookup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- BBC News
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - '>='
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - '>='
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
name: dalli-elasticache
|
188
|
+
prerelease: false
|
189
|
+
type: :runtime
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
requirement: !ruby/object:Gem::Requirement
|
183
197
|
requirements:
|
@@ -210,6 +224,7 @@ files:
|
|
210
224
|
- Rakefile
|
211
225
|
- alephant-lookup.gemspec
|
212
226
|
- lib/alephant/lookup.rb
|
227
|
+
- lib/alephant/lookup/lookup_cache.rb
|
213
228
|
- lib/alephant/lookup/lookup_helper.rb
|
214
229
|
- lib/alephant/lookup/lookup_location.rb
|
215
230
|
- lib/alephant/lookup/lookup_query.rb
|