trilogy_aurora 0.1.1 → 0.3.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 +4 -4
- data/.rspec +1 -1
- data/.rubocop.yml +5 -23
- data/README.md +16 -12
- data/Rakefile +17 -5
- data/compose.yml +7 -0
- data/lib/trilogy_aurora/client.rb +95 -0
- data/lib/trilogy_aurora/version.rb +1 -1
- data/lib/trilogy_aurora.rb +2 -109
- metadata +21 -19
- data/.dockerignore +0 -11
- data/CHANGELOG.md +0 -5
- data/Dockerfile +0 -20
- data/docker-compose.yml +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35db8108014a6e21a985a21fbce35d8ecea1e50a610e0b90d0311494f7e766ac
|
4
|
+
data.tar.gz: c798f7504199f039eb435c9055ab4fbda470cb87f72afe07c0a8a4b14562a0dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d8844c208b6cd107473b7da1b3cf35e7b87f614249e64ace04f538850731b272896e2ff727b2c1981d3f4e4c53e0080d6b19a958c5c02459157f5efb6802fe6
|
7
|
+
data.tar.gz: b0e9e837a24f5f71153dc774cbcbcd5a8a83d310f02acecd84da0779d64b36a1c5c1280f4c8577cc84493bd11d4fed2d00fad6656cd5eceaa7d3b9943bab961a
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
plugins:
|
2
2
|
- rubocop-rake
|
3
3
|
- rubocop-rspec
|
4
4
|
|
@@ -6,29 +6,11 @@ AllCops:
|
|
6
6
|
TargetRubyVersion: 3.0
|
7
7
|
NewCops: enable
|
8
8
|
|
9
|
-
Style/StringLiterals:
|
10
|
-
Enabled: true
|
11
|
-
EnforcedStyle: double_quotes
|
12
|
-
|
13
|
-
Style/StringLiteralsInInterpolation:
|
14
|
-
Enabled: true
|
15
|
-
EnforcedStyle: double_quotes
|
16
|
-
|
17
|
-
Layout/LineLength:
|
18
|
-
Max: 120
|
19
|
-
|
20
9
|
Metrics/MethodLength:
|
21
|
-
Max:
|
22
|
-
|
23
|
-
RSpec/Focus:
|
24
|
-
Enabled: true
|
25
|
-
AutoCorrect: false
|
26
|
-
|
27
|
-
RSpec/MultipleExpectations:
|
28
|
-
Max: 2
|
29
|
-
|
30
|
-
RSpec/NestedGroups:
|
31
|
-
Max: 5
|
10
|
+
Max: 25
|
32
11
|
|
33
12
|
RSpec/MessageSpies:
|
34
13
|
Enabled: false
|
14
|
+
|
15
|
+
RSpec/NestedGroups:
|
16
|
+
Max: 4
|
data/README.md
CHANGED
@@ -14,11 +14,13 @@ Essentially, the [mysql2-aurora](https://github.com/alfa-jpn/mysql2-aurora) gem
|
|
14
14
|
|
15
15
|
Install the gem and add to the application's Gemfile by executing:
|
16
16
|
|
17
|
-
|
17
|
+
```shell
|
18
|
+
bundle add trilogy_aurora
|
19
|
+
```
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
21
|
-
In addition to existing initialization options for `Trilogy`, you can now also use the `
|
23
|
+
In addition to existing initialization options for `Trilogy`, you can now also use the `aurora_disconnect_on_readonly` and `aurora_max_retry` options.
|
22
24
|
|
23
25
|
```ruby
|
24
26
|
Trilogy.new(
|
@@ -32,14 +34,12 @@ Trilogy.new(
|
|
32
34
|
|
33
35
|
with Rails >= 7.1, in `database.yml`
|
34
36
|
|
35
|
-
```
|
37
|
+
```yaml
|
36
38
|
development:
|
37
|
-
adapter:
|
38
|
-
|
39
|
-
username: root
|
40
|
-
password: change_me
|
41
|
-
aurora_max_retry: 5
|
39
|
+
adapter: trilogy
|
40
|
+
# ...
|
42
41
|
aurora_disconnect_on_readonly: true
|
42
|
+
aurora_max_retry: 5
|
43
43
|
```
|
44
44
|
|
45
45
|
From the README of [mysql2-aurora](https://github.com/alfa-jpn/mysql2-aurora):
|
@@ -77,10 +77,14 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/a-lavi
|
|
77
77
|
|
78
78
|
## Testing
|
79
79
|
|
80
|
+
Run Rubocop + RSpec
|
81
|
+
|
80
82
|
```shell
|
81
|
-
|
82
|
-
|
83
|
+
bundle exec rake
|
84
|
+
```
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
+
Clean up
|
87
|
+
|
88
|
+
```shell
|
89
|
+
docker compose down
|
86
90
|
```
|
data/Rakefile
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
5
|
|
6
|
-
RSpec::Core::RakeTask.new(:
|
6
|
+
RSpec::Core::RakeTask.new(spec: :mysql)
|
7
7
|
|
8
|
-
require
|
8
|
+
require 'rubocop/rake_task'
|
9
9
|
|
10
10
|
RuboCop::RakeTask.new
|
11
11
|
|
12
|
-
task default: %i[spec
|
12
|
+
task default: %i[rubocop spec]
|
13
|
+
|
14
|
+
desc 'Ensure MySQL is available'
|
15
|
+
task :mysql do
|
16
|
+
sh 'docker compose up --detach mysql &> /dev/null'
|
17
|
+
catch :ready do
|
18
|
+
loop do
|
19
|
+
sh 'docker compose run --rm mysql mysql -h mysql -e "SELECT 1" &> /dev/null' do |ok|
|
20
|
+
ok ? throw(:ready) : sleep(1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/compose.yml
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'trilogy'
|
4
|
+
|
5
|
+
module TrilogyAurora
|
6
|
+
# Trilogy Aurora wrapper
|
7
|
+
class Client
|
8
|
+
attr_reader :trilogy
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@trilogy = TrilogyAurora::Trilogy.new(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Disconnect and re-initialize TrilogyAurora::Trilogy
|
15
|
+
def reconnect!
|
16
|
+
disconnect!
|
17
|
+
|
18
|
+
@trilogy = TrilogyAurora::Trilogy.new(@trilogy.connection_options.dup)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Close TrilogyAurora::Trilogy connection
|
22
|
+
def disconnect!
|
23
|
+
trilogy&.close
|
24
|
+
rescue StandardError
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Execute a TrilogyAurora::Trilogy query, disconnecting or reconnecting after read-only errors
|
29
|
+
# based on initialization options.
|
30
|
+
def query(...) # rubocop:disable Metrics/AbcSize
|
31
|
+
try_count = 0
|
32
|
+
|
33
|
+
begin
|
34
|
+
trilogy.query(...)
|
35
|
+
rescue TrilogyAurora::Trilogy::Error => e
|
36
|
+
raise unless e.message&.include?('--read-only')
|
37
|
+
|
38
|
+
try_count += 1
|
39
|
+
|
40
|
+
if trilogy.connection_options[:aurora_disconnect_on_readonly]
|
41
|
+
warn <<~WARNING
|
42
|
+
[trilogy_aurora] Database is readonly, Aurora failover event likely occured. \
|
43
|
+
Closing database connection
|
44
|
+
WARNING
|
45
|
+
disconnect!
|
46
|
+
elsif try_count <= trilogy.connection_options[:aurora_max_retry]
|
47
|
+
retry_interval_seconds = [1.5 * (try_count - 1), 10].min
|
48
|
+
warn <<~WARNING
|
49
|
+
[trilogy_aurora] Database is readonly. \
|
50
|
+
Retry after #{retry_interval_seconds} seconds
|
51
|
+
WARNING
|
52
|
+
sleep retry_interval_seconds
|
53
|
+
reconnect!
|
54
|
+
retry
|
55
|
+
end
|
56
|
+
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Delegate instance method calls to TrilogyAurora::Trilogy instance.
|
62
|
+
def method_missing(...)
|
63
|
+
trilogy.public_send(...)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Delegate `respond_to?` to TrilogyAurora::Trilogy instance.
|
67
|
+
def respond_to_missing?(...)
|
68
|
+
trilogy.respond_to?(...)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Delegate class method calls to TrilogyAurora::Trilogy.
|
72
|
+
def self.method_missing(...)
|
73
|
+
TrilogyAurora::Trilogy.public_send(...)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Delegate `respond_to?` to TrilogyAurora::Trilogy.
|
77
|
+
def self.respond_to_missing?(...)
|
78
|
+
TrilogyAurora::Trilogy.respond_to?(...)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Delegate const reference to TrilogyAurora::Trilogy.
|
82
|
+
def self.const_missing(...)
|
83
|
+
TrilogyAurora::Trilogy.const_get(...)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Delegate `const_defined?` to TrilogyAurora::Trilogy.
|
87
|
+
def self.const_defined?(...)
|
88
|
+
TrilogyAurora::Trilogy.const_defined?(...)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Trilogy = Object.send(:remove_const, :Trilogy)
|
93
|
+
end
|
94
|
+
|
95
|
+
Trilogy = TrilogyAurora::Client
|
data/lib/trilogy_aurora.rb
CHANGED
@@ -1,111 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require
|
5
|
-
|
6
|
-
# This module contains Trilogy, a wrapper around ::Trilogy that handles read-only errors from Aurora.
|
7
|
-
#
|
8
|
-
# It also contains the original ::Trilogy class as ORIGINAL_TRILOGY_CLASS.
|
9
|
-
module TrilogyAurora
|
10
|
-
# A wrapper around ::Trilogy that handles read-only errors from Aurora.
|
11
|
-
class Trilogy
|
12
|
-
# The ::Trilogy instance.
|
13
|
-
attr_reader :trilogy
|
14
|
-
|
15
|
-
# Pass in any options that ::Trilogy accepts.
|
16
|
-
#
|
17
|
-
# Additionally, you can pass in the `aurora_max_retry` and `aurora_disconnect_on_readonly` options:
|
18
|
-
#
|
19
|
-
# - `aurora_max_retry` is the number of times to retry a query when it fails due to a read-only error.
|
20
|
-
# The default is 5.
|
21
|
-
#
|
22
|
-
# - `aurora_disconnect_on_readonly` is a boolean that determines whether or not to disconnect from the database
|
23
|
-
# after a read-only error is encountered.
|
24
|
-
# The default is false.
|
25
|
-
def initialize(opts)
|
26
|
-
@opts = opts&.transform_keys(&:to_sym)
|
27
|
-
@max_retry = @opts.delete(:aurora_max_retry) || 5
|
28
|
-
@disconnect_only = @opts.delete(:aurora_disconnect_on_readonly) || false
|
29
|
-
reconnect!
|
30
|
-
end
|
31
|
-
|
32
|
-
# Execute a ::Trilogy query, disconnecting or reconnecting after read-only errors
|
33
|
-
# based on initialization options.
|
34
|
-
def query(...)
|
35
|
-
try_count = 0
|
36
|
-
|
37
|
-
begin
|
38
|
-
trilogy.query(...)
|
39
|
-
rescue TrilogyAurora::ORIGINAL_TRILOGY_CLASS::Error => e
|
40
|
-
raise e unless e.message&.include?("--read-only")
|
41
|
-
|
42
|
-
try_count += 1
|
43
|
-
|
44
|
-
if @disconnect_only
|
45
|
-
warn(
|
46
|
-
"[trilogy_aurora] Database is readonly, Aurora failover event likely occured, closing database connection"
|
47
|
-
)
|
48
|
-
disconnect!
|
49
|
-
elsif try_count <= @max_retry
|
50
|
-
retry_interval_seconds = [1.5 * (try_count - 1), 10].min
|
51
|
-
|
52
|
-
warn "[trilogy_aurora] Database is readonly. Retry after #{retry_interval_seconds}seconds"
|
53
|
-
sleep retry_interval_seconds
|
54
|
-
reconnect!
|
55
|
-
retry
|
56
|
-
end
|
57
|
-
|
58
|
-
raise e
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# Disconnect and re-initialize ::Trilogy
|
63
|
-
def reconnect!
|
64
|
-
disconnect!
|
65
|
-
|
66
|
-
@trilogy = TrilogyAurora::ORIGINAL_TRILOGY_CLASS.new(@opts)
|
67
|
-
end
|
68
|
-
|
69
|
-
# Close ::Trilogy connection
|
70
|
-
def disconnect!
|
71
|
-
@trilogy&.close
|
72
|
-
rescue StandardError
|
73
|
-
nil
|
74
|
-
end
|
75
|
-
|
76
|
-
# Delegate instance method calls to ::Trilogy instance.
|
77
|
-
def method_missing(name, ...)
|
78
|
-
trilogy.public_send(name, ...)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Delegate `respond_to?` to ::Trilogy instance.
|
82
|
-
def respond_to_missing?(name, ...)
|
83
|
-
trilogy.respond_to?(name, ...)
|
84
|
-
end
|
85
|
-
|
86
|
-
# Delegate class method calls to ::Trilogy.
|
87
|
-
def self.method_missing(name, ...)
|
88
|
-
TrilogyAurora::ORIGINAL_TRILOGY_CLASS.public_send(name, ...)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Delegate `respond_to?` to ::Trilogy.
|
92
|
-
def self.respond_to_missing?(name, ...)
|
93
|
-
TrilogyAurora::ORIGINAL_TRILOGY_CLASS.respond_to?(name, ...)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Delegate const reference to ::Trilogy.
|
97
|
-
def self.const_missing(name)
|
98
|
-
TrilogyAurora::ORIGINAL_TRILOGY_CLASS.const_get(name)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Delegate `const_defined?` to ::Trilogy.
|
102
|
-
def self.const_defined?(name, ...)
|
103
|
-
TrilogyAurora::ORIGINAL_TRILOGY_CLASS.const_defined?(name, ...)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# The original ::Trilogy class.
|
108
|
-
ORIGINAL_TRILOGY_CLASS = ::Trilogy
|
109
|
-
# Swap out the original ::Trilogy class with our wrapper (Trilogy).
|
110
|
-
::Trilogy = TrilogyAurora::Trilogy
|
111
|
-
end
|
3
|
+
require 'trilogy_aurora/version'
|
4
|
+
require 'trilogy_aurora/client'
|
metadata
CHANGED
@@ -1,53 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trilogy_aurora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aidan Lavis
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-05-07 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
13
|
+
name: bigdecimal
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '3.0'
|
18
|
+
version: '0'
|
23
19
|
type: :runtime
|
24
20
|
prerelease: false
|
25
21
|
version_requirements: !ruby/object:Gem::Requirement
|
26
22
|
requirements:
|
27
23
|
- - ">="
|
28
24
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: trilogy
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.5'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
31
38
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
-
description:
|
39
|
+
version: '2.5'
|
34
40
|
email:
|
35
41
|
- aidanlavis@gmail.com
|
36
42
|
executables: []
|
37
43
|
extensions: []
|
38
44
|
extra_rdoc_files: []
|
39
45
|
files:
|
40
|
-
- ".dockerignore"
|
41
46
|
- ".rdoc_options"
|
42
47
|
- ".rspec"
|
43
48
|
- ".rubocop.yml"
|
44
|
-
- CHANGELOG.md
|
45
|
-
- Dockerfile
|
46
49
|
- LICENSE.txt
|
47
50
|
- README.md
|
48
51
|
- Rakefile
|
49
|
-
-
|
52
|
+
- compose.yml
|
50
53
|
- lib/trilogy_aurora.rb
|
54
|
+
- lib/trilogy_aurora/client.rb
|
51
55
|
- lib/trilogy_aurora/version.rb
|
52
56
|
homepage: https://github.com/a-lavis/trilogy_aurora
|
53
57
|
licenses:
|
@@ -56,7 +60,6 @@ metadata:
|
|
56
60
|
homepage_uri: https://github.com/a-lavis/trilogy_aurora
|
57
61
|
source_code_uri: https://github.com/a-lavis/trilogy_aurora
|
58
62
|
rubygems_mfa_required: 'true'
|
59
|
-
post_install_message:
|
60
63
|
rdoc_options: []
|
61
64
|
require_paths:
|
62
65
|
- lib
|
@@ -71,8 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
74
|
- !ruby/object:Gem::Version
|
72
75
|
version: '0'
|
73
76
|
requirements: []
|
74
|
-
rubygems_version: 3.
|
75
|
-
signing_key:
|
77
|
+
rubygems_version: 3.6.5
|
76
78
|
specification_version: 4
|
77
79
|
summary: Adds AWS Aurora failover support to Trilogy.
|
78
80
|
test_files: []
|
data/.dockerignore
DELETED
data/CHANGELOG.md
DELETED
data/Dockerfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
ARG RUBY_VERSION=3.2
|
2
|
-
|
3
|
-
FROM ruby:${RUBY_VERSION}-alpine
|
4
|
-
|
5
|
-
ARG TRILOGY_VERSION
|
6
|
-
|
7
|
-
ENV TRILOGY_VERSION=$TRILOGY_VERSION
|
8
|
-
|
9
|
-
# Create application directory.
|
10
|
-
RUN mkdir /app
|
11
|
-
WORKDIR /app
|
12
|
-
|
13
|
-
# Install packages
|
14
|
-
RUN apk upgrade && apk add --update build-base git linux-headers libxml2-dev libxslt-dev mariadb-dev ruby-dev tzdata yaml-dev zlib-dev
|
15
|
-
|
16
|
-
# Deploy application
|
17
|
-
ADD . /app
|
18
|
-
|
19
|
-
# Install gems
|
20
|
-
RUN sh /app/bin/setup
|
data/docker-compose.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
services:
|
2
|
-
app:
|
3
|
-
build:
|
4
|
-
context: .
|
5
|
-
environment:
|
6
|
-
TEST_DB_HOST: 'mysql'
|
7
|
-
TEST_DB_USER: 'root'
|
8
|
-
TEST_DB_PASS: ''
|
9
|
-
volumes:
|
10
|
-
- .:/app
|
11
|
-
depends_on:
|
12
|
-
mysql:
|
13
|
-
condition: service_healthy
|
14
|
-
mysql:
|
15
|
-
image: mysql:8.0
|
16
|
-
environment:
|
17
|
-
MYSQL_ROOT_PASSWORD: ''
|
18
|
-
MYSQL_ALLOW_EMPTY_PASSWORD: 1
|
19
|
-
healthcheck:
|
20
|
-
test: ["CMD-SHELL", "mysqladmin ping -h mysql"]
|
21
|
-
interval: 10s
|
22
|
-
timeout: 5s
|
23
|
-
retries: 3
|