alephant-broker 1.2.1 → 1.3.1

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