umbra-rb 0.1.4.pre → 0.3.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
  SHA256:
3
- metadata.gz: 679e800927f9e68d4db11021a503382982a875ffe2603225733e41fcbecea043
4
- data.tar.gz: 917c3503760f10e01849b3c57b6d9e61410f2b1d523407b128f96387fdcf212a
3
+ metadata.gz: 4afc323984fc7ba817ef3e2d6d80d7f6de5e628d5efbb149b0b4194285c3adba
4
+ data.tar.gz: bacebcf43acd0a5fe79f59ea5675395cb1201209c30493d4ac3b85f047635722
5
5
  SHA512:
6
- metadata.gz: 705b476de7c8caf4fc74b20b5bcd4852f6794785ed07f0778aabcd846cbf520aac6060c7e715bc79e59f02468da828f371344393aa0f45ba5dbc208180eba666
7
- data.tar.gz: 0c06e66a03e07d85f73f1b66de8b31efa8fcd18c81f267279140e970ada23f0455df5d789719775242699c5f4bd53b544d7aea7e356c7ed66f1cde4c86cf5ac8
6
+ metadata.gz: ea48085756d9af9944a47857499ef825cb0fa8a821db4a79e6f549981da233f31d85f107afcb0084bb703ba9621994936991f0e7e7cdf43787fbe3ee48ee29e3
7
+ data.tar.gz: 2a13babc32f10a410ecee4a10cda257b47080ee83200aaaf2007bff46881b83ba1e11e48d42b795f8714779122712c4e39133ca1245f32b59f39a54b82d3d5a3
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_WITH: "local_deals_service"
data/.standard.yml ADDED
@@ -0,0 +1,2 @@
1
+ ignore:
2
+ - 'lib/umbra/pb/**/*'
data/Gemfile CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in umbra.gemspec
6
5
  gemspec
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "standard/rake"
5
4
 
6
5
  RSpec::Core::RakeTask.new(:spec)
7
6
 
data/bin/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path("../lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require "bundler/setup"
7
+ require "umbra"
8
+ require "pry"
9
+
10
+ Pry.start
data/config.ru ADDED
@@ -0,0 +1,13 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "rack"
5
+ require "rack/lobster"
6
+ require "puma"
7
+ require "umbra"
8
+ require "pry"
9
+
10
+ Umbra.configure
11
+
12
+ use Umbra::Middleware
13
+ run Rack::Lobster.new
data/lib/umbra.rb CHANGED
@@ -1,26 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'typhoeus'
4
- require 'redis'
5
- require 'multi_json'
3
+ require "zeitwerk"
4
+ require "rack"
5
+ require "redis"
6
+ require "concurrent"
7
+
8
+ Zeitwerk::Loader.for_gem.setup
6
9
 
7
10
  module Umbra
8
- autoload :Config, 'umbra/config'
9
- autoload :Encoder, 'umbra/encoder'
10
- autoload :Middleware, 'umbra/middleware'
11
- autoload :Publisher, 'umbra/publisher'
12
- autoload :Subscriber, 'umbra/subscriber'
13
- autoload :RequestBuilder, 'umbra/request_builder'
14
- autoload :ShadowRequester, 'umbra/shadow_requester'
15
- autoload :SynchronousPublisher, 'umbra/synchronous_publisher'
16
- autoload :Version, 'umbra/version'
17
-
18
- CHANNEL = 'umbra_channel'
19
- HEADER_KEY = 'HTTP_X_UMBRA_REQUEST'
20
- HEADER_VALUE = 'true'
11
+ autoload :Pb, "umbra/pb/umbra_pb"
12
+
13
+ CHANNEL = "umbra_channel"
14
+ HEADER_KEY = "HTTP_X_UMBRA_REQUEST"
15
+ HEADER_VALUE = "true"
21
16
 
22
17
  RequestSelector = proc { true }
23
- SuppressErrorHandler = proc { nil }
18
+ SuppressErrorHandler = proc {}
24
19
 
25
20
  class << self
26
21
  attr_reader :config
@@ -31,16 +26,17 @@ module Umbra
31
26
  test_redis_connection!
32
27
  end
33
28
 
34
- def publish(env, response)
29
+ def publish(env)
35
30
  return if umbra_request?(env)
31
+
36
32
  return unless @config
37
- return unless @config.request_selector.call(env, response)
33
+ return unless @config.request_selector.call(env)
38
34
 
39
- env['umbra.request_body'] = request_body(env)
35
+ env["umbra.request_body"] = request_body(env)
40
36
 
41
- @config.publisher.call(env, response)
42
- rescue StandardError => e
43
- @config.error_handler.call(e, env, response)
37
+ @config.publisher.call(env)
38
+ rescue => e
39
+ @config.error_handler.call(e, env)
44
40
  end
45
41
 
46
42
  def redis
@@ -63,7 +59,7 @@ module Umbra
63
59
  private
64
60
 
65
61
  def request_body(env)
66
- io = env.fetch('rack.input')
62
+ io = env.fetch("rack.input")
67
63
  io.rewind
68
64
  body = io.read
69
65
  io.rewind
@@ -72,13 +68,13 @@ module Umbra
72
68
  end
73
69
 
74
70
  def test_redis_connection!
75
- logger.info '[umbra] Testing redis connection...'
71
+ logger.info "[umbra] Testing redis connection..."
76
72
  redis.ping
77
- logger.info '[umbra] redis is alive!'
73
+ logger.info "[umbra] redis is alive!"
78
74
  rescue Redis::BaseError => e
79
75
  logger.warn "[umbra] error while connecting to redis: #{e.message}"
80
76
  reset!
81
- rescue StandardError => e
77
+ rescue => e
82
78
  logger.warn "[umbra] redis is misconfigured: #{e.message}"
83
79
  reset!
84
80
  end
data/lib/umbra/config.rb CHANGED
@@ -4,12 +4,12 @@ module Umbra
4
4
 
5
5
  def self.default(&block)
6
6
  new(
7
- publisher: Publisher,
7
+ publisher: Publisher.new,
8
8
  request_selector: RequestSelector,
9
9
  encoder: Encoder,
10
10
  error_handler: SuppressErrorHandler,
11
11
  redis_options: {},
12
- logger: Logger.new(STDOUT),
12
+ logger: Logger.new($stdout),
13
13
  &block
14
14
  )
15
15
  end
data/lib/umbra/encoder.rb CHANGED
@@ -2,61 +2,47 @@
2
2
 
3
3
  module Umbra
4
4
  class Encoder
5
- def self.call(env, response)
6
- new(env, response).call
5
+ def self.call(env)
6
+ new(env).call
7
7
  end
8
8
 
9
- def initialize(env, response)
9
+ def initialize(env)
10
10
  @env = env
11
- @status, @headers, @body = response
12
- end
13
-
14
- def to_h
15
- @to_h ||=
16
- {
17
- 'request' => {
18
- 'scheme' => @env.fetch('rack.url_scheme'),
19
- 'host' => @env['HTTP_HOST'] || @env.fetch('SERVER_NAME'),
20
- 'uri' => @env.fetch('REQUEST_URI'),
21
- 'port' => @env.fetch('SERVER_PORT'),
22
- 'method' => @env.fetch('REQUEST_METHOD'),
23
- 'query' => @env.fetch('QUERY_STRING'),
24
- 'script_name' => @env.fetch('SCRIPT_NAME'),
25
- 'path_info' => @env.fetch('PATH_INFO'),
26
- 'headers' => request_headers,
27
- 'body' => request_body
28
- },
29
- 'response' => {
30
- 'status' => @status,
31
- 'headers' => @headers,
32
- 'body' => body_string
33
- }
34
- }
35
11
  end
36
12
 
37
13
  def call
38
- @call ||= MultiJson.dump(to_h)
14
+ @call ||= Pb::Message.new(
15
+ method: rack_request.request_method,
16
+ url: rack_request.url,
17
+ body: request_body,
18
+ headers: request_headers
19
+ ).to_proto
20
+ end
21
+
22
+ def ignored_headers
23
+ []
39
24
  end
40
25
 
41
26
  private
42
27
 
43
- def request_headers
44
- @request_headers ||= @env.select { |k, _| k.start_with?('HTTP_') }
28
+ def rack_request
29
+ @rack_request ||= Rack::Request.new(@env)
45
30
  end
46
31
 
47
- def request_body
48
- @env.fetch('umbra.request_body')
32
+ def request_headers
33
+ @request_headers ||=
34
+ @env
35
+ .select { |k, _| k.start_with?("HTTP_") && !ignored_headers.include?(k) }
36
+ .merge(HEADER_KEY => HEADER_VALUE)
37
+ .transform_keys { |k| to_http_header(k) }
49
38
  end
50
39
 
51
- def body_string
52
- @body_string ||=
53
- begin
54
- str = []
55
-
56
- @body.each { |x| str << x.to_s }
40
+ def to_http_header(rack_header)
41
+ rack_header.delete_prefix("HTTP_").downcase.split("_").join("-")
42
+ end
57
43
 
58
- str.join('')
59
- end
44
+ def request_body
45
+ @env.fetch("umbra.request_body")
60
46
  end
61
47
  end
62
48
  end
@@ -5,11 +5,9 @@ module Umbra
5
5
  end
6
6
 
7
7
  def call(env)
8
- response = @app.call(env)
8
+ Umbra.publish(env.dup)
9
9
 
10
- Umbra.publish(env, response)
11
-
12
- response
10
+ @app.call(env)
13
11
  end
14
12
  end
15
13
  end
@@ -0,0 +1,21 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: umbra.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_file("umbra.proto", :syntax => :proto3) do
8
+ add_message "umbra.pb.Message" do
9
+ optional :method, :string, 1
10
+ optional :url, :string, 2
11
+ map :headers, :string, :string, 3
12
+ optional :body, :bytes, 4
13
+ end
14
+ end
15
+ end
16
+
17
+ module Umbra
18
+ module Pb
19
+ Message = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("umbra.pb.Message").msgclass
20
+ end
21
+ end
@@ -1,55 +1,32 @@
1
1
  module Umbra
2
- class Publisher < SynchronousPublisher
3
- MAX_QUEUE_SIZE = 100
4
-
5
- class << self
6
- def call(env, response)
7
- start_once!
8
-
9
- if @queue.size > MAX_QUEUE_SIZE
10
- Umbra.logger.warn '[umbra] Publish queue at max - dropping items'
11
- return
12
- end
13
-
14
- @queue.push(proc { super(env, response) })
15
- end
16
-
17
- private
18
-
19
- # rubocop:disable Metrics/MethodLength
20
- def start_once!
21
- LOCK.synchronize do
22
- return if @started == Process.pid
23
-
24
- Umbra.logger.info '[umbra] Starting publishing thread'
25
-
26
- @started = Process.pid
27
- @queue = Queue.new
2
+ class Publisher
3
+ DEFAULT_MAX_QUEUE = 100
4
+ DEFAULT_MIN_THREADS = 1
5
+ DEFAULT_MAX_THREADS = 1
6
+
7
+ attr_reader :pool
8
+
9
+ def initialize(**options)
10
+ @pool = Concurrent::CachedThreadPool.new(
11
+ min_threads: options.fetch(:min_threads, DEFAULT_MIN_THREADS),
12
+ max_threads: options.fetch(:max_thread, DEFAULT_MAX_THREADS),
13
+ max_queue: options.fetch(:max_queue, DEFAULT_MAX_QUEUE),
14
+ fallback_policy: :abort
15
+ )
16
+ end
28
17
 
29
- worker_thread = Thread.new do
30
- while (x = @queue.pop)
31
- break if x == STOP
18
+ def call(env, encoder: Umbra.encoder, redis: Umbra.redis)
19
+ @pool << proc { call!(env, encoder: encoder, redis: redis) }
32
20
 
33
- begin
34
- x.call
35
- rescue StandardError => e
36
- Umbra.logger.warn '[umbra] Error in publishing thread'
37
- Umbra.config.error_handler.call(e)
38
- end
39
- end
40
- end
21
+ true
22
+ rescue Concurrent::RejectedExecutionError
23
+ Umbra.logger.warn "[umbra] Queue at max - dropping items"
41
24
 
42
- at_exit do
43
- @queue.push(STOP)
44
- worker_thread.join
45
- end
46
- end
47
- end
48
- # rubocop:enable Metrics/MethodLength
25
+ false
49
26
  end
50
27
 
51
- STOP = Object.new
52
- LOCK = Mutex.new
53
- private_constant :STOP, :LOCK
28
+ def call!(env, encoder: Umbra.encoder, redis: Umbra.redis)
29
+ redis.publish(Umbra::CHANNEL, encoder.call(env))
30
+ end
54
31
  end
55
32
  end
data/lib/umbra/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Umbra
4
- VERSION = '0.1.4.pre'
4
+ VERSION = "0.3.0"
5
5
  end
data/umbra-rb.gemspec CHANGED
@@ -1,38 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'umbra/version'
5
+
6
+ require "umbra/version"
6
7
 
7
8
  Gem::Specification.new do |spec|
8
- spec.name = 'umbra-rb'
9
- spec.version = Umbra::VERSION
10
- spec.authors = ['carwow Developers']
11
- spec.email = ['developers@carwow.co.uk']
9
+ spec.name = "umbra-rb"
10
+ spec.version = Umbra::VERSION
11
+ spec.authors = ["carwow Developers"]
12
+ spec.email = ["developers@carwow.co.uk"]
13
+
14
+ spec.summary = "A shadow requesting library for rack based applications"
15
+ spec.homepage = "https://github.com/carwow/umbra"
16
+ spec.license = "MIT"
12
17
 
13
- spec.summary = 'A shadow requesting library for rack based applications'
14
- spec.homepage = 'https://github.com/carwow/umbra'
15
- spec.license = 'MIT'
18
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["github_repo"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
16
22
 
17
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
- spec.metadata['homepage_uri'] = spec.homepage
19
- spec.metadata['source_code_uri'] = spec.homepage
23
+ spec.require_paths = ["lib"]
20
24
 
21
- # Specify which files should be added to the gem when it is released.
22
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
25
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ `git ls-files -z`
27
+ .split("\x0")
28
+ .reject { |f| f.match(%r{^(test|spec|features)/}) }
25
29
  end
26
- spec.require_paths = ['lib']
27
-
28
- spec.add_development_dependency 'bundler', '~> 2.0'
29
- spec.add_development_dependency 'carwow_rubocop'
30
- spec.add_development_dependency 'pry'
31
- spec.add_development_dependency 'rake', '~> 10.0'
32
- spec.add_development_dependency 'rspec', '~> 3.0'
33
-
34
- spec.add_dependency 'multi_json', '~> 1.13'
35
- spec.add_dependency 'oj', '~> 3.9'
36
- spec.add_dependency 'redis', '~> 4.1'
37
- spec.add_dependency 'typhoeus', '~> 1.3'
30
+
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
+ spec.add_development_dependency "standard"
33
+ spec.add_development_dependency "pry"
34
+ spec.add_development_dependency "rake", "~> 13.0"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ spec.add_development_dependency "rack-test"
37
+ spec.add_development_dependency "puma"
38
+
39
+ spec.add_dependency "concurrent-ruby", "~> 1.1"
40
+ spec.add_dependency "redis", "~> 4.1"
41
+ spec.add_dependency "google-protobuf", "~> 3"
42
+ spec.add_dependency "rack", "~> 2"
43
+ spec.add_dependency "zeitwerk", "~> 2"
38
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: umbra-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4.pre
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - carwow Developers
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-26 00:00:00.000000000 Z
11
+ date: 2021-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: carwow_rubocop
28
+ name: standard
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '13.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '13.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -81,33 +81,47 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: multi_json
84
+ name: rack-test
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.13'
90
- type: :runtime
89
+ version: '0'
90
+ type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '1.13'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: oj
98
+ name: puma
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: concurrent-ruby
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '3.9'
117
+ version: '1.1'
104
118
  type: :runtime
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: '3.9'
124
+ version: '1.1'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: redis
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -123,44 +137,67 @@ dependencies:
123
137
  - !ruby/object:Gem::Version
124
138
  version: '4.1'
125
139
  - !ruby/object:Gem::Dependency
126
- name: typhoeus
140
+ name: google-protobuf
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - "~>"
130
144
  - !ruby/object:Gem::Version
131
- version: '1.3'
145
+ version: '3'
132
146
  type: :runtime
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
- version: '1.3'
139
- description:
152
+ version: '3'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rack
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2'
167
+ - !ruby/object:Gem::Dependency
168
+ name: zeitwerk
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '2'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '2'
181
+ description:
140
182
  email:
141
183
  - developers@carwow.co.uk
142
184
  executables: []
143
185
  extensions: []
144
186
  extra_rdoc_files: []
145
187
  files:
146
- - ".circleci/config.yml"
147
- - ".gitignore"
188
+ - ".bundle/config"
148
189
  - ".rspec"
149
- - ".rubocop.yml"
190
+ - ".standard.yml"
150
191
  - Gemfile
151
- - Gemfile.lock
152
- - LICENSE.txt
153
- - README.md
154
192
  - Rakefile
193
+ - bin/console
194
+ - config.ru
155
195
  - lib/umbra.rb
156
196
  - lib/umbra/config.rb
157
197
  - lib/umbra/encoder.rb
158
198
  - lib/umbra/middleware.rb
199
+ - lib/umbra/pb/umbra_pb.rb
159
200
  - lib/umbra/publisher.rb
160
- - lib/umbra/request_builder.rb
161
- - lib/umbra/shadow_requester.rb
162
- - lib/umbra/subscriber.rb
163
- - lib/umbra/synchronous_publisher.rb
164
201
  - lib/umbra/version.rb
165
202
  - umbra-rb.gemspec
166
203
  homepage: https://github.com/carwow/umbra
@@ -169,8 +206,9 @@ licenses:
169
206
  metadata:
170
207
  allowed_push_host: https://rubygems.org
171
208
  homepage_uri: https://github.com/carwow/umbra
209
+ github_repo: https://github.com/carwow/umbra
172
210
  source_code_uri: https://github.com/carwow/umbra
173
- post_install_message:
211
+ post_install_message:
174
212
  rdoc_options: []
175
213
  require_paths:
176
214
  - lib
@@ -181,12 +219,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
181
219
  version: '0'
182
220
  required_rubygems_version: !ruby/object:Gem::Requirement
183
221
  requirements:
184
- - - ">"
222
+ - - ">="
185
223
  - !ruby/object:Gem::Version
186
- version: 1.3.1
224
+ version: '0'
187
225
  requirements: []
188
- rubygems_version: 3.0.3
189
- signing_key:
226
+ rubygems_version: 3.1.4
227
+ signing_key:
190
228
  specification_version: 4
191
229
  summary: A shadow requesting library for rack based applications
192
230
  test_files: []
data/.circleci/config.yml DELETED
@@ -1,59 +0,0 @@
1
- ruby: &ruby
2
- image: carwow/ruby-ci:2.6
3
-
4
- redis: &redis
5
- image: redis
6
-
7
- version: 2
8
-
9
- jobs:
10
- bundle:
11
- working_directory: ~/umbra
12
- docker:
13
- - *ruby
14
- steps:
15
- - checkout
16
- - restore_cache:
17
- keys:
18
- - bundle-{{ checksum "Gemfile.lock" }}
19
- - bundle-
20
- - run: |
21
- bundle config --local path vendor/bundle &&
22
- bundle check || bundle install --jobs=4 --retry=3
23
- - save_cache:
24
- key: bundle-{{ checksum "Gemfile.lock" }}
25
- paths: [~/umbra/vendor/bundle]
26
- - persist_to_workspace:
27
- root: '~'
28
- paths: [umbra]
29
-
30
- rubocop:
31
- working_directory: ~/umbra
32
- docker:
33
- - *ruby
34
- steps:
35
- - attach_workspace:
36
- at: '~'
37
- - run: bundle exec rubocop
38
-
39
- tests:
40
- working_directory: ~/umbra
41
- docker:
42
- - *ruby
43
- - *redis
44
- steps:
45
- - attach_workspace:
46
- at: '~'
47
- - run: |
48
- bundle exec rspec
49
-
50
- workflows:
51
- version: 2
52
- build:
53
- jobs:
54
- - bundle
55
- - rubocop:
56
- requires: [bundle]
57
- - tests:
58
- requires: [bundle]
59
-
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
12
- *.gem
data/.rubocop.yml DELETED
@@ -1,9 +0,0 @@
1
- inherit_gem:
2
- carwow_rubocop:
3
- - default.yml
4
-
5
- Metrics/MethodLength:
6
- Max: 20
7
-
8
- Metrics/AbcSize:
9
- Max: 20
data/Gemfile.lock DELETED
@@ -1,77 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- umbra-rb (0.1.4.pre)
5
- multi_json (~> 1.13)
6
- oj (~> 3.9)
7
- redis (~> 4.1)
8
- typhoeus (~> 1.3)
9
-
10
- GEM
11
- remote: https://rubygems.org/
12
- specs:
13
- ast (2.4.0)
14
- carwow_rubocop (3.0.3)
15
- rubocop (>= 0.68)
16
- rubocop-performance
17
- rubocop-rspec
18
- coderay (1.1.2)
19
- diff-lcs (1.3)
20
- ethon (0.12.0)
21
- ffi (>= 1.3.0)
22
- ffi (1.11.1)
23
- jaro_winkler (1.5.3)
24
- method_source (0.9.2)
25
- multi_json (1.13.1)
26
- oj (3.9.1)
27
- parallel (1.17.0)
28
- parser (2.6.4.1)
29
- ast (~> 2.4.0)
30
- pry (0.12.2)
31
- coderay (~> 1.1.0)
32
- method_source (~> 0.9.0)
33
- rainbow (3.0.0)
34
- rake (10.5.0)
35
- redis (4.1.3)
36
- rspec (3.8.0)
37
- rspec-core (~> 3.8.0)
38
- rspec-expectations (~> 3.8.0)
39
- rspec-mocks (~> 3.8.0)
40
- rspec-core (3.8.2)
41
- rspec-support (~> 3.8.0)
42
- rspec-expectations (3.8.4)
43
- diff-lcs (>= 1.2.0, < 2.0)
44
- rspec-support (~> 3.8.0)
45
- rspec-mocks (3.8.1)
46
- diff-lcs (>= 1.2.0, < 2.0)
47
- rspec-support (~> 3.8.0)
48
- rspec-support (3.8.2)
49
- rubocop (0.74.0)
50
- jaro_winkler (~> 1.5.1)
51
- parallel (~> 1.10)
52
- parser (>= 2.6)
53
- rainbow (>= 2.2.2, < 4.0)
54
- ruby-progressbar (~> 1.7)
55
- unicode-display_width (>= 1.4.0, < 1.7)
56
- rubocop-performance (1.4.1)
57
- rubocop (>= 0.71.0)
58
- rubocop-rspec (1.35.0)
59
- rubocop (>= 0.60.0)
60
- ruby-progressbar (1.10.1)
61
- typhoeus (1.3.1)
62
- ethon (>= 0.9.0)
63
- unicode-display_width (1.6.0)
64
-
65
- PLATFORMS
66
- ruby
67
-
68
- DEPENDENCIES
69
- bundler (~> 2.0)
70
- carwow_rubocop
71
- pry
72
- rake (~> 10.0)
73
- rspec (~> 3.0)
74
- umbra-rb!
75
-
76
- BUNDLED WITH
77
- 2.0.2
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2019 Christian Gregg
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
data/README.md DELETED
@@ -1,83 +0,0 @@
1
- # umbra :waning_crescent_moon:
2
-
3
- > **umbra** /ˈʌmbrə/
4
- >
5
- > noun
6
- > 1. the fully shaded inner region of a shadow cast by an opaque object, especially the area on the earth or moon experiencing the total phase of an eclipse.
7
- > 2. shadow or darkness.
8
- > "an impenetrable umbra seemed to fill every inch of the museum"
9
-
10
- `umbra` is a rack middleware that allows you to create shadow requests via a redis pub/sub channel.
11
-
12
- # Installation
13
-
14
- Add this to your `Gemfile`
15
-
16
- ```ruby
17
- gem 'umbra-rb'
18
- ```
19
-
20
- And then execute:
21
-
22
- $ bundle
23
-
24
- Or install it yourself as:
25
-
26
- $ gem install umbra-rb
27
-
28
-
29
- ## Usage
30
-
31
- A minimal rack application using `umbra` would look like this:
32
-
33
- ```ruby
34
- # /config.ru
35
- require 'rack'
36
- require 'rack/lobster'
37
- require 'umbra'
38
-
39
- Umbra.configure
40
-
41
- use Umbra::Middleware
42
- run Rack::Lobster.new
43
-
44
- ```
45
-
46
- If using Rails you can achieve the same via an initializer:
47
-
48
- ```ruby
49
- # /config/initializers/umbra.rb
50
- require 'umbra'
51
-
52
- Umbra.configure
53
-
54
- Rails.application.config.middleware.use(Umbra::Middleware)
55
- ```
56
-
57
- Then, in another process, you can start receiving each request via an `Umbra::Subscriber`.
58
- `Umbra::Subscriber` can be initialized with anything response to `.call`. For example:
59
-
60
- ```ruby
61
- Umbra::Subscriber.new(
62
- proc { |payload| puts "New Request: #{payload}" }
63
- ).start
64
- ```
65
-
66
- The `payload` is the encoded request and response, as defined by the configured encoder. By default, this is `Umbra::Encoder`.
67
-
68
- `umbra` also provides some helper classes for common use cases:
69
-
70
- - `Umbra::RequestBuilder` takes the default encoding and returns a `Typhoeus::Request` object.
71
- - `Umbra::ShadowRequester` can be configured to shadow requests `count:` times using a `pool:` of threads via a thread queue.
72
- - More to come...
73
-
74
-
75
- # Config
76
-
77
- ## Contributing
78
-
79
- Bug reports and pull requests are welcome on GitHub at https://github.com/carwow/umbra.
80
-
81
- ## License
82
-
83
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Umbra
4
- class RequestBuilder
5
- UMBRA_HEADERS = {
6
- Umbra::HEADER_KEY => Umbra::HEADER_VALUE,
7
- 'HTTP_CACHE_CONTROL' => 'no-cache, no-store, private, max-age=0'
8
- }.freeze
9
-
10
- class << self
11
- def call(env)
12
- Typhoeus::Request.new(
13
- base_url(env) + url(env),
14
- method: method(env),
15
- body: body(env),
16
- headers: headers(env)
17
- )
18
- end
19
-
20
- private
21
-
22
- def headers(env)
23
- request(env)
24
- .fetch('headers')
25
- .merge(UMBRA_HEADERS)
26
- .transform_keys { |key| key.split('_').drop(1).map(&:capitalize).join('-') }
27
- end
28
-
29
- def method(env)
30
- request(env).fetch('method').downcase.to_sym
31
- end
32
-
33
- def body(env)
34
- request(env).fetch('body')
35
- end
36
-
37
- def url(env)
38
- request = request(env)
39
- query = request.fetch('query')
40
- path = request.fetch('script_name') + request.fetch('path_info')
41
-
42
- query.empty? ? path : path + "?#{query}"
43
- end
44
-
45
- def base_url(env)
46
- request = request(env)
47
- scheme = request.fetch('scheme')
48
- host = request.fetch('host')
49
-
50
- "#{scheme}://#{host}"
51
- end
52
-
53
- def request(env)
54
- env.fetch('request')
55
- end
56
- end
57
- end
58
- end
@@ -1,60 +0,0 @@
1
- module Umbra
2
- class ShadowRequester
3
- def initialize(count: 1, pool: 1, max_queue_size: 100)
4
- @count = count
5
- @pool = pool
6
- @queue = Queue.new
7
- @stop = Object.new
8
- @lock = Mutex.new
9
- @max_queue_size = max_queue_size
10
- end
11
-
12
- def call(env)
13
- start_worker!
14
-
15
- if @queue.size > @max_queue_size
16
- Umbra.logger.warn '[umbra] Shadowing queue at max - dropping items'
17
- return
18
- end
19
-
20
- request = RequestBuilder.call(env)
21
-
22
- @count.times { @queue.push(request) }
23
- end
24
-
25
- private
26
-
27
- # rubocop:disable Metrics/MethodLength
28
- def start_worker!
29
- @lock.synchronize do
30
- return if @started
31
-
32
- @started = true
33
- Umbra.logger.info '[umbra] Starting shadowing threads...'
34
-
35
- workers = (0...@pool).map do |thread_num|
36
- Thread.new do
37
- Umbra.logger.info "[umbra] shadow thread #{thread_num} waiting"
38
-
39
- while (request = @queue.pop)
40
- break if request == @stop
41
-
42
- begin
43
- request.run
44
- rescue StandardError => e
45
- Umbra.logger.warn "[umbra] error in shadow thread #{thread_num}"
46
- Umbra.config.error_handler.call(e)
47
- end
48
- end
49
- end
50
- end
51
-
52
- at_exit do
53
- @pool.times { @queue.push(@stop) }
54
- workers.map(&:join)
55
- end
56
- end
57
- end
58
- # rubocop:enable Metrics/MethodLength
59
- end
60
- end
@@ -1,15 +0,0 @@
1
- module Umbra
2
- class Subscriber
3
- def initialize(worker)
4
- @worker = worker
5
- end
6
-
7
- def start
8
- Umbra.redis.subscribe(Umbra::CHANNEL) do |on|
9
- on.message do |_, message|
10
- @worker.call(MultiJson.load(message))
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,7 +0,0 @@
1
- module Umbra
2
- class SynchronousPublisher
3
- def self.call(env, response, encoder: Umbra.encoder, redis: Umbra.redis)
4
- redis.publish(Umbra::CHANNEL, encoder.call(env, response))
5
- end
6
- end
7
- end