fly-ruby 0.3.0 → 0.4.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: 506556ce79da83a817f5a6a56b336328912730ace3fb26d10ed0d7e97f971abc
4
- data.tar.gz: c2c7ceb044a6a9054da36ae775a0693458e91dac271b5d341666995dd59373b5
3
+ metadata.gz: ea1ca64bcd11ed8a60774f0d8ec255ffb49bc6b8e21a8bd32e7410068bec35c0
4
+ data.tar.gz: fb55ad6c98cb631bf202aea206c53a9b2e9a7c738cd9835095dd647011cfc7f6
5
5
  SHA512:
6
- metadata.gz: d7a79ba9b2a2db74515bdce0c606c99072d292813b5ef34c8963d44bcc0366fe0230bc784dcb8e489614ef1dd33ebb447d7cb215fd7f475c0fc00d51487446cf
7
- data.tar.gz: 38e26c8853bde15845b1cd1c34bcff68f5f87db5a8e726af4451329619b54f3c4dfa26ffd83832e24ea0a743401b1e28c011316ab78b08c60cc76e42022bec58
6
+ metadata.gz: 7c3df04f8bb9f97bfb87903b0fffc14ef2b320802e1183752c07f8b769b629f6c66af21ae0e4bb5a23a2608cfdfdda2f3b1c387e3edcd1f64b5d2474a79f7a6f
7
+ data.tar.gz: ff4ca7c18d4b18ec237c8e1c59bce88dce849198934ed1d42c28ab2a081b577f8fa2cc38930d0478ec94a5bee580e2f12649b38d3ad46d176a774edaba60446c
data/.gitignore CHANGED
@@ -4,3 +4,4 @@ log/
4
4
  Gemfile.lock
5
5
  .ruby-version
6
6
  *.gem
7
+ db/
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  [![Test](https://github.com/superfly/fly-ruby/actions/workflows/test.yml/badge.svg)](https://github.com/superfly/fly-ruby/actions/workflows/test.yml)
2
2
 
3
- This gem contains helper code and Rack middleware for deploying Ruby web apps on [Fly.io](https://fly.io). Supported features:
3
+ This gem contains helper code and Rack middleware for deploying Ruby web apps on [Fly.io](https://fly.io). It's designed to speed up apps by using region-local Postgresql replicas for database reads. See the blog post for more details:
4
4
 
5
- * Speed up apps by using region-local Postgresql replicas for database reads
5
+ https://fly.io/blog/run-ordinary-rails-apps-globally
6
6
 
7
7
  ## Speed up apps using region-local database replicas
8
8
 
@@ -49,7 +49,7 @@ Fly.configure do |c|
49
49
  end
50
50
  ```
51
51
 
52
- See [the source code](https://github.com/soupedup/fly-rails/blob/main/lib/fly-rails/configuration.rb) for defaults and available configuration options.
52
+ See [the source code](https://github.com/superfly/fly-ruby/blob/main/lib/fly-ruby/configuration.rb) for defaults and available configuration options.
53
53
  ## Known issues
54
54
 
55
55
  This middleware send all requests to the primary if you do something like update a user's database session on every GET request.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fly
2
4
  class Configuration
3
5
  # Set the region where this instance of the application is deployed
@@ -28,6 +30,9 @@ module Fly
28
30
  attr_accessor :database_url
29
31
  attr_accessor :redis_url
30
32
 
33
+ # An array of string representations of exceptions that should trigger a replay
34
+ attr_accessor :replayable_exceptions
35
+
31
36
  def initialize
32
37
  self.primary_region = ENV["PRIMARY_REGION"]
33
38
  self.current_region = ENV["FLY_REGION"]
@@ -40,6 +45,19 @@ module Fly
40
45
  self.replay_threshold_in_seconds = 5
41
46
  self.database_url = ENV[database_url_env_var]
42
47
  self.redis_url = ENV[redis_url_env_var]
48
+ self.replayable_exceptions = ["SQLite3::CantOpenException", "PG::ReadOnlySqlTransaction"]
49
+ end
50
+
51
+ def replayable_exception_classes
52
+ @replayable_exception_classes ||= replayable_exceptions.collect {|ex| module_exists?(ex) }.compact
53
+ @replayable_exception_classes
54
+ end
55
+
56
+ def module_exists?(module_name)
57
+ mod = Module.const_get(module_name)
58
+ return mod
59
+ rescue NameError
60
+ nil
43
61
  end
44
62
 
45
63
  def database_uri
@@ -60,9 +78,9 @@ module Fly
60
78
  # Rails-compatible database configuration
61
79
  def regional_database_config
62
80
  {
63
- "host" => regional_database_host,
64
- "port" => 5433,
65
- "adapter" => "postgresql"
81
+ :host => regional_database_host,
82
+ :port => 5433,
83
+ :adapter => "postgresql"
66
84
  }
67
85
  end
68
86
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fly
4
+ class Headers
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ status, headers, body = @app.call(env)
11
+ response = Rack::Response.new(body, status, headers)
12
+ response.set_header('Fly-Region', ENV['FLY_REGION'])
13
+ response.finish
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Fly::Railtie < Rails::Railtie
2
4
  def hijack_database_connection
3
5
  ActiveSupport::Reloader.to_prepare do
@@ -6,26 +8,17 @@ class Fly::Railtie < Rails::Railtie
6
8
  # hooks for forking servers to work correctly.
7
9
  if defined?(ActiveRecord)
8
10
  config = ActiveRecord::Base.connection_db_config.configuration_hash
9
- ActiveRecord::Base.establish_connection(config.merge(Fly.configuration.regional_database_config))
10
- end
11
- end
12
- end
13
-
14
- # Set useful headers for debugging
15
- def set_debug_response_headers
16
- ActiveSupport::Reloader.to_prepare do
17
- ApplicationController.send(:after_action) do
18
- response.headers['Fly-Region'] = ENV['FLY_REGION']
11
+ ActiveRecord::Base.establish_connection(config.symbolize_keys.merge(Fly.configuration.regional_database_config))
19
12
  end
20
13
  end
21
14
  end
22
15
 
23
16
  initializer("fly.regional_database") do |app|
24
- set_debug_response_headers if Fly.configuration.web?
17
+ # Insert the request middleware high in the stack, but after static file delivery
18
+ app.config.middleware.insert_after ActionDispatch::Executor, Fly::Headers if Fly.configuration.web?
25
19
 
26
20
  if Fly.configuration.eligible_for_activation?
27
- # Insert the request interceptor high in the stack, but after static file delivery
28
- app.config.middleware.insert_after ActionDispatch::Executor, Fly::RegionalDatabase::ReplayableRequestMiddleware
21
+ app.config.middleware.insert_after Fly::Headers, Fly::RegionalDatabase::ReplayableRequestMiddleware
29
22
  # Insert the database exception handler at the bottom of the stack to take priority over other exception handlers
30
23
  app.config.middleware.use Fly::RegionalDatabase::DbExceptionHandlerMiddleware
31
24
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
 
3
5
  module Fly
@@ -29,9 +31,10 @@ module Fly
29
31
  end
30
32
 
31
33
  def call(env)
34
+ exceptions = Fly.configuration.replayable_exception_classes
32
35
  @app.call(env)
33
- rescue PG::ReadOnlySqlTransaction, ActiveRecord::StatementInvalid => e
34
- if e.is_a?(PG::ReadOnlySqlTransaction) || e&.cause&.is_a?(PG::ReadOnlySqlTransaction)
36
+ rescue *exceptions, ActiveRecord::RecordInvalid => e
37
+ if exceptions.any? {|ex| e.is_a?(ex) } || exceptions.any? { e&.cause&.is_a?(e) }
35
38
  RegionalDatabase.replay_in_primary_region!(state: "captured_write")
36
39
  else
37
40
  raise e
@@ -53,7 +56,7 @@ module Fly
53
56
  end
54
57
 
55
58
  def replay_request_state(header_value)
56
- header_value&.scan(/(.*?)=(.*?)($|;)/)&.detect { |v| v[0] == "state" }&.at(1)
59
+ header_value&.slice(/(?:^|;)state=([^;]*)/, 1)
57
60
  end
58
61
 
59
62
  def call(env)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fly
2
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
3
5
  end
data/lib/fly-ruby.rb CHANGED
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "fly-ruby/configuration"
2
4
  require_relative "fly-ruby/regional_database"
5
+ require_relative "fly-ruby/headers"
6
+
3
7
  require "forwardable"
4
8
 
5
9
  if defined?(::Rails)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fly-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Sierles
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-21 00:00:00.000000000 Z
11
+ date: 2022-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -41,6 +41,7 @@ files:
41
41
  - fly-ruby.gemspec
42
42
  - lib/fly-ruby.rb
43
43
  - lib/fly-ruby/configuration.rb
44
+ - lib/fly-ruby/headers.rb
44
45
  - lib/fly-ruby/railtie.rb
45
46
  - lib/fly-ruby/regional_database.rb
46
47
  - lib/fly-ruby/version.rb
@@ -63,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
64
  - !ruby/object:Gem::Version
64
65
  version: '0'
65
66
  requirements: []
66
- rubygems_version: 3.2.3
67
+ rubygems_version: 3.2.26
67
68
  signing_key:
68
69
  specification_version: 4
69
70
  summary: Augment Ruby web apps for deployment in Fly.io