alephant-broker 1.2.1 → 1.3.1

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: 7188ad7416429b9e3644497b893e54d17cf18848
4
- data.tar.gz: 600553f7caaceb30285b9454192211cdc8b49773
3
+ metadata.gz: 54b3da006e03b9b1bb3a4697ef59e5472a872481
4
+ data.tar.gz: b6fb65f722c3cb34f5589327dc1478244d1367fb
5
5
  SHA512:
6
- metadata.gz: e880ac06f905b8d4e56b4ec9e25f601d2c0996bcd37321a25d3779c951139ab08c150499e6c5f688fa35505150b04cc7378e769c3ee6d7ea2ea8a7bb0595c4a3
7
- data.tar.gz: 93191cbd238306a803f607520522d2ee02018c36fdb9d4e8c5435a2fed4a050a24ebb566a97e84a45cd1b4d834847ace817087f51ac6b6df2d9ba3096599a984
6
+ metadata.gz: dc7a8957b4a78a63681e211df68fb18a8bd27c48093a858afab1a394bcc07809666c36f3ac5e711e2726372c306385fb53e1099bc274753a6b7b74e3e562554c
7
+ data.tar.gz: 6b16b372746c156f6ec2a93c7f906985f88e25e5445df00d4539b1d0567c3408889d2b6f85ab85c99194a820af74c0f187649cb5e4b6341215cb5ae41cd6134a
data/Rakefile CHANGED
@@ -3,7 +3,6 @@ $:.unshift File.join(File.dirname(__FILE__), 'lib')
3
3
  require 'rspec/core/rake_task'
4
4
  require 'bundler/gem_tasks'
5
5
  require 'alephant/broker'
6
-
7
- RSpec::Core::RakeTask.new(:spec)
6
+ require 'rake/rspec'
8
7
 
9
8
  task :default => :spec
@@ -25,16 +25,16 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "pry"
26
26
  spec.add_development_dependency "pry-remote"
27
27
  spec.add_development_dependency "pry-nav"
28
+ spec.add_development_dependency "rake-rspec", ">= 0.0.2"
28
29
 
29
30
  spec.add_development_dependency "bundler", "~> 1.5"
30
31
  spec.add_development_dependency "rake"
31
32
  spec.add_development_dependency "rack-test"
32
33
 
33
- spec.add_runtime_dependency "request_store"
34
- spec.add_runtime_dependency "peach"
35
34
  spec.add_runtime_dependency "alephant-lookup"
36
35
  spec.add_runtime_dependency "alephant-cache"
37
36
  spec.add_runtime_dependency 'alephant-logger'
38
37
  spec.add_runtime_dependency 'alephant-sequencer'
39
38
  spec.add_runtime_dependency "dalli-elasticache"
39
+ spec.add_runtime_dependency 'pmap'
40
40
  end
@@ -8,8 +8,8 @@ module Alephant
8
8
  module Broker
9
9
  @@poll = true
10
10
 
11
- def self.handle(env)
12
- Request::Handler.process env
11
+ def self.handle(load_strategy, env)
12
+ Request::Handler.process(load_strategy, env)
13
13
  end
14
14
 
15
15
  def self.config
@@ -29,8 +29,11 @@ module Alephant
29
29
  end
30
30
 
31
31
  class Application
32
- def initialize(c = nil)
32
+ attr_reader :load_strategy
33
+
34
+ def initialize(load_strategy, c = nil)
33
35
  Broker.config = c unless c.nil?
36
+ @load_strategy = load_strategy
34
37
  end
35
38
 
36
39
  def call(env)
@@ -46,19 +49,16 @@ module Alephant
46
49
  end
47
50
 
48
51
  def response_for(call_environment)
49
- Broker.handle call_environment
52
+ Broker.handle(load_strategy, call_environment)
50
53
  end
51
54
 
52
55
  def send(response)
53
56
  [
54
57
  response.status,
55
- {
56
- "Content-Type" => response.content_type,
57
- "X-Sequence" => response.sequence.to_s,
58
- "X-Version" => response.version.to_s,
59
- "X-Cached" => response.cached.to_s
60
- }.merge(response.headers),
61
- [ response.content.to_s ]
58
+ response.headers,
59
+ [
60
+ response.content.to_s
61
+ ]
62
62
  ]
63
63
  end
64
64
 
@@ -8,89 +8,42 @@ require 'alephant/broker/cache'
8
8
 
9
9
  module Alephant
10
10
  module Broker
11
-
12
11
  class Component
13
- include Logger
14
-
15
- attr_reader :id, :batch_id, :options, :content, :content_type, :cached
12
+ attr_reader :id, :batch_id, :options, :content, :opts_hash
16
13
 
17
- def initialize(id, batch_id, options)
18
- @id = id
19
- @batch_id = batch_id
20
- @cache = Cache::Client.new
21
- @options = symbolize(options || {})
22
- @cached = true
14
+ def initialize(meta, data)
15
+ @id = meta.id
16
+ @batch_id = meta.batch_id
17
+ @options = symbolize(meta.options || {})
18
+ @content = data[:content].force_encoding 'UTF-8'
19
+ @opts_hash = meta.opts_hash
20
+ @data = data
21
+ @meta = meta
23
22
  end
24
23
 
25
- def load
26
- @content_type = cache_object[:content_type]
27
- @content = cache_object[:content]
28
- rescue
29
- content_hash = @cache.set(cache_key, retrieve_object)
30
- @content_type = content_hash[:content_type]
31
- @content = content_hash[:content]
24
+ def content_type
25
+ headers['Content-Type']
32
26
  end
33
27
 
34
- def opts_hash
35
- @opts_hash ||= Crimp.signature(options)
28
+ def headers
29
+ {
30
+ 'Content-Type' => data[:content_type].to_s,
31
+ 'X-Version' => meta.version.to_s,
32
+ 'X-Cached' => meta.cached.to_s
33
+ }.merge(data[:headers] || {})
36
34
  end
37
35
 
38
- def version
39
- @version ||= sequencer.get_last_seen
36
+ def status
37
+ 200
40
38
  end
41
39
 
42
40
  private
43
41
 
44
- def cache_object
45
- @cache_object ||= @cache.get(cache_key) { retrieve_object }
46
- end
47
-
48
- def retrieve_object
49
- @cached = false
50
- s3.get(s3_path)
51
- end
52
-
53
- def cache_key
54
- @cache_key ||= "#{id}/#{opts_hash}/#{version}"
55
- end
42
+ attr_reader :meta, :data
56
43
 
57
44
  def symbolize(hash)
58
45
  Hash[hash.map { |k,v| [k.to_sym, v] }]
59
46
  end
60
-
61
- def s3
62
- @s3_cache ||= Alephant::Cache.new(
63
- Broker.config[:s3_bucket_id],
64
- Broker.config[:s3_object_path]
65
- )
66
- end
67
-
68
- def s3_path
69
- lookup.read(id, options, version).tap do |lookup_object|
70
- raise InvalidCacheKey if lookup_object.location.nil?
71
- end.location unless version.nil?
72
- end
73
-
74
- def lookup
75
- @lookup ||= Alephant::Lookup.create(Broker.config[:lookup_table_name])
76
- end
77
-
78
- def key
79
- batch_id.nil? ? component_key : renderer_key
80
- end
81
-
82
- def component_key
83
- "#{id}/#{opts_hash}"
84
- end
85
-
86
- def renderer_key
87
- "#{batch_id}/#{opts_hash}"
88
- end
89
-
90
- def sequencer
91
- @sequencer ||= Alephant::Sequencer.create(Broker.config[:sequencer_table_name], key)
92
- end
93
-
94
47
  end
95
48
  end
96
49
  end
@@ -0,0 +1,30 @@
1
+ require 'alephant/broker/component_meta'
2
+ require 'alephant/broker/errors/content_not_found'
3
+ require 'alephant/broker/error_component'
4
+ require 'alephant/logger'
5
+
6
+ module Alephant
7
+ module Broker
8
+ class ComponentFactory
9
+ include Logger
10
+
11
+ def initialize(load_strategy)
12
+ @load_strategy = load_strategy
13
+ end
14
+
15
+ def create(id, batch_id, options)
16
+ component_meta = ComponentMeta.new(id, batch_id, options)
17
+ Component.new(
18
+ component_meta,
19
+ @load_strategy.load(component_meta)
20
+ )
21
+ rescue Alephant::Broker::Errors::ContentNotFound
22
+ logger.warn 'Broker.ComponentFactory.create: Exception raised (ContentNotFound)'
23
+ ErrorComponent.new(component_meta, 404)
24
+ rescue => e
25
+ logger.warn("Broker.ComponentFactory.create: Exception raised (#{e.message}, #{e.backtrace.join('\n')})")
26
+ ErrorComponent.new(component_meta, 500, e)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,51 @@
1
+ module Alephant
2
+ module Broker
3
+ class ComponentMeta
4
+ attr_reader :id, :options, :batch_id
5
+ attr_accessor :cached
6
+
7
+ def initialize(id, batch_id, options)
8
+ @id = id
9
+ @batch_id = batch_id
10
+ @options = options
11
+ @cached = true
12
+ end
13
+
14
+ def cache_key
15
+ "#{id}/#{opts_hash}/#{version}"
16
+ end
17
+
18
+ def version
19
+ Broker.config.fetch(
20
+ 'elasticache_cache_version', 'not available'
21
+ ).to_s
22
+ end
23
+
24
+ def key
25
+ batch_id.nil? ? component_key : renderer_key
26
+ end
27
+
28
+ def opts_hash
29
+ Crimp.signature options
30
+ end
31
+
32
+ private
33
+
34
+ def component_key
35
+ "#{id}/#{opts_hash}"
36
+ end
37
+
38
+ def renderer_key
39
+ "#{batch_id}/#{opts_hash}"
40
+ end
41
+
42
+ def headers(data)
43
+ {
44
+ 'Content-Type' => data[:content_type].to_s,
45
+ 'X-Version' => version.to_s,
46
+ 'X-Cached' => cached.to_s
47
+ }.merge(data[:headers] || {})
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,42 @@
1
+ module Alephant
2
+ module Broker
3
+ class ErrorComponent
4
+ attr_reader :batch_id, :content, :id, :options, :status
5
+
6
+ def initialize(meta, status, body = nil)
7
+ @batch_id = meta.batch_id
8
+ @status = status
9
+ @content = content_for body
10
+ @id = meta.id
11
+ @options = {}
12
+ end
13
+
14
+ def content_type
15
+ headers['Content-Type']
16
+ end
17
+
18
+ def headers
19
+ {
20
+ 'Content-Type' => 'text/plain'
21
+ }
22
+ end
23
+
24
+ private
25
+
26
+ STATUS_CODE_MAPPING = {
27
+ 404 => 'Not found',
28
+ 500 => 'Error retrieving content'
29
+ }
30
+
31
+ def content_for(body)
32
+ body.nil? ? STATUS_CODE_MAPPING[status]
33
+ : format_content_for(body)
34
+ end
35
+
36
+ def format_content_for(body)
37
+ body.is_a? Exception ? "#{e.message}\n#{e.backtrace.join('\n')}"
38
+ : body
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ module Alephant
2
+ module Broker
3
+ module Errors
4
+ class ContentNotFound < StandardError; end
5
+ end
6
+ end
7
+ end
@@ -1,11 +1,9 @@
1
1
  module Alephant
2
2
  module Broker
3
3
  class InvalidCacheKey < Exception
4
-
5
4
  def initialize
6
- super("Cache key not found based on component_id and options combination")
5
+ super 'Cache key not found based on component_id and options combination'
7
6
  end
8
-
9
7
  end
10
8
  end
11
9
  end
@@ -0,0 +1,88 @@
1
+ require "alephant/broker/cache"
2
+ require 'alephant/broker/errors/content_not_found'
3
+ require 'alephant/broker/errors/invalid_cache_key'
4
+
5
+ module Alephant
6
+ module Broker
7
+ module LoadStrategy
8
+ class S3
9
+ def load(component_meta)
10
+ add_s3_headers(
11
+ cache_object(component_meta),
12
+ component_meta
13
+ )
14
+ rescue
15
+ add_s3_headers(
16
+ cache.set(
17
+ component_meta.cache_key,
18
+ retrieve_object(component_meta)
19
+ ),
20
+ component_meta
21
+ )
22
+ end
23
+
24
+ private
25
+
26
+ def add_s3_headers(component_data, component_meta)
27
+ component_data.merge(
28
+ { headers: headers(component_meta) }
29
+ )
30
+ end
31
+
32
+ def cache
33
+ @cache ||= Cache::Client.new
34
+ end
35
+
36
+ def headers(component_meta)
37
+ { 'X-Sequence' => sequence(component_meta).to_s }
38
+ end
39
+
40
+ def sequence(component_meta)
41
+ sequencer(component_meta).get_last_seen
42
+ end
43
+
44
+ def retrieve_object(component_meta)
45
+ component_meta.cached = false
46
+ s3.get s3_path(component_meta)
47
+ rescue AWS::S3::Errors::NoSuchKey, InvalidCacheKey
48
+ raise Alephant::Broker::Errors::ContentNotFound
49
+ end
50
+
51
+ def cache_object(component_meta)
52
+ cache.get(component_meta.cache_key) do
53
+ retrieve_object component_meta
54
+ end
55
+ end
56
+
57
+ def s3
58
+ @s3 ||= Alephant::Cache.new(
59
+ Broker.config[:s3_bucket_id],
60
+ Broker.config[:s3_object_path]
61
+ )
62
+ end
63
+
64
+ def s3_path(component_meta)
65
+ lookup.read(
66
+ component_meta.id,
67
+ component_meta.options,
68
+ sequence(component_meta)
69
+ ).tap do |obj|
70
+ raise InvalidCacheKey if obj.location.nil?
71
+ end.location unless sequence(component_meta).nil?
72
+ end
73
+
74
+ def lookup
75
+ @lookup ||= Alephant::Lookup.create(
76
+ Broker.config[:lookup_table_name]
77
+ )
78
+ end
79
+
80
+ def sequencer(component_meta)
81
+ Alephant::Sequencer.create(
82
+ Broker.config[:sequencer_table_name], component_meta.key
83
+ )
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -10,7 +10,7 @@ module Alephant
10
10
 
11
11
  attr_accessor :component
12
12
 
13
- def initialize(env = nil)
13
+ def initialize(component_factory, env = nil)
14
14
  return if env.nil?
15
15
 
16
16
  component_id = env.path.split('/')[2] || nil
@@ -18,9 +18,8 @@ module Alephant
18
18
 
19
19
  raise InvalidAssetId.new("No Asset ID specified") if component_id.nil?
20
20
 
21
- @component = Component.new(component_id, nil, options)
21
+ @component = component_factory.create(component_id, nil, options)
22
22
  end
23
-
24
23
  end
25
24
  end
26
25
  end