fly-ruby 0.3.0 → 0.4.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
  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