alephant-lookup 1.0.0 → 2.0.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.
- 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
|