Use the new SQLite3::Database#busy_handler_timeout= method for a non-GVL-blocking, fair retry interval busy handler implementation

Co-Authored-By: Jean Boussier <byroot@ruby-lang.org>
This commit is contained in:
Stephen Margheim 2024-05-30 21:18:46 +02:00 committed by Jean Boussier
parent 8bf495a622
commit 2976d3767e
7 changed files with 19 additions and 10 deletions

View File

@ -153,7 +153,7 @@ platforms :ruby, :windows do
gem "nokogiri", ">= 1.8.1", "!= 1.11.0" gem "nokogiri", ">= 1.8.1", "!= 1.11.0"
# Active Record. # Active Record.
gem "sqlite3", ">= 1.6.6" gem "sqlite3", ">= 2.0"
group :db do group :db do
gem "pg", "~> 1.3" gem "pg", "~> 1.3"

View File

@ -690,7 +690,7 @@ DEPENDENCIES
sidekiq sidekiq
sneakers sneakers
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
sqlite3 (>= 1.6.6) sqlite3 (>= 2.0)
stackprof stackprof
stimulus-rails stimulus-rails
sucker_punch sucker_punch

View File

@ -1,3 +1,9 @@
* Replace `SQLite3::Database#busy_timeout` with `#busy_handler_timeout=`
Provides a non-GVL-blocking, fair retry interval busy handler implementation
*Stephen Margheim*
* SQLite3Adapter: Translate `SQLite3::BusyException` into `ActiveRecord::StatementTimeout`. * SQLite3Adapter: Translate `SQLite3::BusyException` into `ActiveRecord::StatementTimeout`.
*Matthew Nguyen* *Matthew Nguyen*

View File

@ -11,7 +11,7 @@ require "active_record/connection_adapters/sqlite3/schema_definitions"
require "active_record/connection_adapters/sqlite3/schema_dumper" require "active_record/connection_adapters/sqlite3/schema_dumper"
require "active_record/connection_adapters/sqlite3/schema_statements" require "active_record/connection_adapters/sqlite3/schema_statements"
gem "sqlite3", ">= 1.4" gem "sqlite3", ">= 2.0"
require "sqlite3" require "sqlite3"
module ActiveRecord module ActiveRecord
@ -783,12 +783,15 @@ module ActiveRecord
if @config[:timeout] && @config[:retries] if @config[:timeout] && @config[:retries]
raise ArgumentError, "Cannot specify both timeout and retries arguments" raise ArgumentError, "Cannot specify both timeout and retries arguments"
elsif @config[:timeout] elsif @config[:timeout]
@raw_connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) timeout = self.class.type_cast_config_to_integer(@config[:timeout])
raise TypeError, "timeout must be integer, not #{timeout}" unless timeout.is_a?(Integer)
@raw_connection.busy_handler_timeout = timeout
elsif @config[:retries] elsif @config[:retries]
ActiveRecord.deprecator.warn(<<~MSG)
The retries option is deprecated and will be removed in Rails 8.0. Use timeout instead.
MSG
retries = self.class.type_cast_config_to_integer(@config[:retries]) retries = self.class.type_cast_config_to_integer(@config[:retries])
raw_connection.busy_handler do |count| raw_connection.busy_handler { |count| count <= retries }
count <= retries
end
end end
super super

View File

@ -223,7 +223,7 @@ module Rails
end end
def gem def gem
["sqlite3", [">= 1.4"]] ["sqlite3", [">= 2.0"]]
end end
def base_package def base_package

View File

@ -449,7 +449,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_config_database_is_added_by_default def test_config_database_is_added_by_default
run_generator run_generator
assert_file "config/database.yml", /sqlite3/ assert_file "config/database.yml", /sqlite3/
assert_gem "sqlite3", '">= 1.4"' assert_gem "sqlite3", '">= 2.0"'
end end
def test_config_mysql_database def test_config_mysql_database

View File

@ -128,7 +128,7 @@ module Rails
assert_file("Gemfile") do |content| assert_file("Gemfile") do |content|
assert_match "# Use sqlite3 as the database for Active Record", content assert_match "# Use sqlite3 as the database for Active Record", content
assert_match 'gem "sqlite3", ">= 1.4"', content assert_match 'gem "sqlite3", ">= 2.0"', content
end end
assert_file("Dockerfile") do |content| assert_file("Dockerfile") do |content|