diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 29819e64..1c798f83 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: ruby-version: [3.2.2] - database: [mysql] + database: [mysql, sqlite] services: mysql: image: mysql:8.0.31 diff --git a/lib/solid_queue/supervisor.rb b/lib/solid_queue/supervisor.rb index c053e803..3f2a1444 100644 --- a/lib/solid_queue/supervisor.rb +++ b/lib/solid_queue/supervisor.rb @@ -117,6 +117,7 @@ def start_runner(runner) pid = fork do runner.start + exit! end forks[pid] = runner diff --git a/test/dummy/config/database.yml b/test/dummy/config/database.yml index 8af24d93..cc9551a1 100644 --- a/test/dummy/config/database.yml +++ b/test/dummy/config/database.yml @@ -5,6 +5,22 @@ # gem "mysql2" # +<% if ENV["TARGET_DB"] == "sqlite" %> +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 50 } %> + retries: 100 + +development: + <<: *default + database: db/development.sqlite + +test: + <<: *default + pool: 20 + database: db/test.sqlite + +<% else %> default: &default adapter: mysql2 username: root @@ -20,3 +36,5 @@ test: <<: *default pool: 20 database: solid_queue_test +<% end %> + diff --git a/test/dummy/config/initializers/sqlite3.rb b/test/dummy/config/initializers/sqlite3.rb new file mode 100644 index 00000000..80d0fec0 --- /dev/null +++ b/test/dummy/config/initializers/sqlite3.rb @@ -0,0 +1,30 @@ +module SqliteImmediateTransactions + def begin_db_transaction + log("begin immediate transaction", "TRANSACTION") do + with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn| + conn.transaction(:immediate) + end + end + end +end + +module SQLite3Configuration + private + def configure_connection + super + + if @config[:retries] + retries = self.class.type_cast_config_to_integer(@config[:retries]) + raw_connection.busy_handler do |count| + (count <= retries).tap { |result| sleep count * 0.001 if result } + end + end + end +end + +ActiveSupport.on_load :active_record do + if defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter) + ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend SqliteImmediateTransactions + ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend SQLite3Configuration + end +end diff --git a/test/dummy/config/solid_queue.yml b/test/dummy/config/solid_queue.yml index df780efe..9ce3cdad 100644 --- a/test/dummy/config/solid_queue.yml +++ b/test/dummy/config/solid_queue.yml @@ -5,7 +5,7 @@ default: &default default: pool_size: 5 scheduler: - polling_interval: 300 + polling_interval: 1 batch_size: 500 development: diff --git a/test/test_helper.rb b/test/test_helper.rb index eb7974f6..e74b20a5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -15,6 +15,16 @@ ActiveSupport::TestCase.fixtures :all end +module BlockLogDeviceTimeoutExceptions + def write(...) + # Prevents TimeoutExceptions from occurring during log writing, where they will be swallowed + # See https://bugs.ruby-lang.org/issues/9115 + Thread.handle_interrupt(Timeout::Error => :never, Timeout::ExitException => :never) { super } + end +end + +Logger::LogDevice.prepend(BlockLogDeviceTimeoutExceptions) + class ActiveSupport::TestCase setup do SolidQueue.logger = ActiveSupport::Logger.new(nil)