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