Last active
April 2, 2021 19:47
-
-
Save mastermatt/a5aa17d84a15f4d0245819751252b1c9 to your computer and use it in GitHub Desktop.
Sequel ConnectionWriteableValidator extension
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen-string-literal: true | |
# The connection_writeable_validator extension modifies a Database to validate | |
# that newly created connections are connected to writeable InnoDB servers. | |
# | |
# Based on advise given by Jeremy Evans | |
# https://groups.google.com/g/sequel-talk/c/JFuxfDuoAZ4/m/hTvgj71uBgAJ | |
# | |
# During an Aurora fail over, new connections may resolve to the old primary | |
# instance, which converts to a ready-only node. | |
# Checking the `innodb_read_only` global variable allows Sequel::Databases | |
# to reject the connection if it connects to a read-only instance. | |
# If rejected, the connection is closed and `connect` is called again on the | |
# adapter for up to `connect_timeout` seconds. | |
# | |
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.BestPractices.html | |
# | |
# | |
module Sequel | |
module ConnectionWriteableValidator | |
def connect(server) | |
# The 2 minute default is absurdly high, but it mirrors the default in the Mysql2 gem. | |
# The expectation is to set a reasonable value in the connection options. | |
timeout = Float(opts[:connect_timeout] || 120) | |
timer = Sequel.start_timer | |
while Sequel.elapsed_seconds_since(timer) < timeout | |
conn = super(server) | |
result = conn.query("SHOW GLOBAL VARIABLES LIKE 'innodb_read_only';") | |
innodb_read_only = (result.first || {})[:Value] != 'OFF' | |
if innodb_read_only | |
log_each(:warn, "#{connection_info(conn)}Connected to read-only server. Disconnecting") | |
disconnect_connection(conn) | |
next | |
end | |
return conn | |
end | |
raise DatabaseConnectionError, 'Unable to create a read/write connection' | |
end | |
end | |
Database.register_extension(:connection_writeable_validator, ConnectionWriteableValidator) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment