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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aff72c4a54e98f1083023e67503f88a7290f0bdb
4
- data.tar.gz: 4570723dbdbd206854ed2d992c82405a8036aaa7
3
+ metadata.gz: 6f7e07c301d41b1ad0433b62cbd83e89d4e1a911
4
+ data.tar.gz: 785873a081b3d684b092f4aa74d408f22dab9141
5
5
  SHA512:
6
- metadata.gz: b912276212e95c51a3b7bddf8d99c1234b8f2df34555625dc7329905b1188c69bb52a120fa9ef851d9f1edc3ce8b366aaede38507c637139eacf05e3a341511e
7
- data.tar.gz: 42ef112c847bb894400f06684b549b6490498e1be173550d20b745361f907a6ef3a4061a8e62fdc61dd816eee4eb14ae0511bd1998e8177cc05e0380120ca5ed
6
+ metadata.gz: 540b154e9875cb1c1977ac87f68c00dbb0b394f2e36f8d3e73703f3f29605e0a1b63ba9f9fbe275804c2e9a094038303d0eea936d0aa8fc3a096c9d39e952010
7
+ data.tar.gz: 992e6df834993e052f6f82ac1cc279a8e774569e4ee6a59c58b6e06fd46c49132c31b3d83bc3fae9e6563e0a01d493d180d6ab378a2a0475448db4238d9da780
@@ -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 'aws-sdk', '~> 1.0'
32
- spec.add_runtime_dependency 'alephant-logger'
33
- spec.add_runtime_dependency 'alephant-support'
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
@@ -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
- LookupQuery.new(lookup_table.table_name, id, opts, batch_version).run!.tap do
25
- logger.info(
26
- "event" => "LookupQuery",
27
- "tableName" => lookup_table.table_name,
28
- "id" => id,
29
- "opts" => opts,
30
- "batchVersion" => batch_version,
31
- "method" => "#{self.class}#read"
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
- @lookup_table.truncate!
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
@@ -1,5 +1,5 @@
1
1
  module Alephant
2
2
  module Lookup
3
- VERSION = "1.0.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -1,11 +1,9 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Alephant::Lookup do
4
- describe ".create(table_name, component_id)" do
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(table_name)" do
15
+ describe "#initialize" do
18
16
  it "calls create on lookup_table" do
19
17
  table = double()
20
- table.should_receive(:table_name)
18
+ expect(table).to receive(:table_name)
21
19
  subject.new(table)
22
20
  end
23
21
  end
24
22
 
25
- describe "#read(id, opts, batch_version)" do
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/9dd916afd5516828a91d259967fd394a"}]
33
+ :attribute_value_list=>[{"s"=>"id/218c835cec343537589dbf1619532e4d"}]
36
34
  },
37
35
  "batch_version"=>{
38
36
  :comparison_operator=>"EQ",
39
- :attribute_value_list=>[{"n"=>"{:variant=>\"foo\"}"}]
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
- AWS::DynamoDB::Client::V20120810
47
- .any_instance
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
- AWS::DynamoDB::Client::V20120810
51
- .any_instance
52
- .should_receive(:query)
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.stub(:table_name).and_return("table_name")
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", 0, {:variant => "foo"})
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
- describe "#write(opts, location)" do
74
- it "does not fail" do
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
- AWS::DynamoDB::Client::V20120810
77
- .any_instance
78
- .stub(:initialize)
79
- .and_return(
80
- double().as_null_object
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
- lookup_table
85
- .should_receive(:table_name)
106
+
107
+ expect(lookup_table)
108
+ .to receive(:table_name)
86
109
  .and_return('test')
87
- lookup_table
88
- .should_receive(:write)
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
- .any_instance
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.stub(:create)
109
- table.should_receive(:table_name)
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: 1.0.0
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: 2015-07-14 00:00:00.000000000 Z
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