diff --git a/README.md b/README.md index f77c4d5a1..8ce987bcd 100644 --- a/README.md +++ b/README.md @@ -385,7 +385,7 @@ All the options available to Active Record for multiple databases can be used he ### Other configuration settings -_Note_: The settings in this section should be set in your `config/application.rb` or your environment config like this: `config.solid_queue.silence_polling = true` +_Note_: The settings in this section should be set in your `config/application.rb` or your environment config like this: `config.solid_queue.silence_queries = true` There are several settings that control how Solid Queue works that you can set as well: - `logger`: the logger you want Solid Queue to use. Defaults to the app logger. @@ -402,7 +402,7 @@ There are several settings that control how Solid Queue works that you can set a - `process_heartbeat_interval`: the heartbeat interval that all processes will follow—defaults to 60 seconds. - `process_alive_threshold`: how long to wait until a process is considered dead after its last heartbeat—defaults to 5 minutes. - `shutdown_timeout`: time the supervisor will wait since it sent the `TERM` signal to its supervised processes before sending a `QUIT` version to them requesting immediate termination—defaults to 5 seconds. -- `silence_polling`: whether to silence Active Record logs emitted when polling for both workers and dispatchers—defaults to `true`. +- `silence_queries`: whether to silence Active Record logs emitted by Solid Queue's internal queries—including polling, heartbeats, concurrency maintenance, and process pruning—defaults to `true`. For backward compatibility, `silence_polling` is still supported as an alias. - `supervisor_pidfile`: path to a pidfile that the supervisor will create when booting to prevent running more than one supervisor in the same host, or in case you want to use it for a health check. It's `nil` by default. - `preserve_finished_jobs`: whether to keep finished jobs in the `solid_queue_jobs` table—defaults to `true`. - `clear_finished_jobs_after`: period to keep finished jobs around, in case `preserve_finished_jobs` is true — defaults to 1 day. When installing Solid Queue, [a recurring job](#recurring-tasks) is automatically configured to clear finished jobs every hour on the 12th minute in batches. You can edit the `recurring.yml` configuration to change this as you see fit. diff --git a/lib/solid_queue.rb b/lib/solid_queue.rb index bd2269e5f..ccc338ea9 100644 --- a/lib/solid_queue.rb +++ b/lib/solid_queue.rb @@ -32,7 +32,7 @@ module SolidQueue mattr_accessor :shutdown_timeout, default: 5.seconds - mattr_accessor :silence_polling, default: true + mattr_accessor :silence_queries, default: true mattr_accessor :supervisor_pidfile mattr_accessor :supervisor, default: false @@ -69,8 +69,21 @@ def supervisor? supervisor end + def silence_queries? + silence_queries + end + + # Backward compatibility: silence_polling is now an alias for silence_queries + def silence_polling=(value) + self.silence_queries = value + end + + def silence_polling + silence_queries + end + def silence_polling? - silence_polling + silence_queries? end def preserve_finished_jobs? diff --git a/lib/solid_queue/app_executor.rb b/lib/solid_queue/app_executor.rb index f315f61a2..0746a6e31 100644 --- a/lib/solid_queue/app_executor.rb +++ b/lib/solid_queue/app_executor.rb @@ -10,6 +10,14 @@ def wrap_in_app_executor(&block) end end + def with_silenced_queries + if SolidQueue.silence_queries? && ActiveRecord::Base.logger + ActiveRecord::Base.logger.silence { yield } + else + yield + end + end + def handle_thread_error(error) SolidQueue.instrument(:thread_error, error: error) diff --git a/lib/solid_queue/dispatcher/concurrency_maintenance.rb b/lib/solid_queue/dispatcher/concurrency_maintenance.rb index 81cf770cc..ffd6078e3 100644 --- a/lib/solid_queue/dispatcher/concurrency_maintenance.rb +++ b/lib/solid_queue/dispatcher/concurrency_maintenance.rb @@ -31,13 +31,17 @@ def stop private def expire_semaphores wrap_in_app_executor do - Semaphore.expired.in_batches(of: batch_size, &:delete_all) + with_silenced_queries do + Semaphore.expired.in_batches(of: batch_size, &:delete_all) + end end end def unblock_blocked_executions wrap_in_app_executor do - BlockedExecution.unblock(batch_size) + with_silenced_queries do + BlockedExecution.unblock(batch_size) + end end end end diff --git a/lib/solid_queue/processes/poller.rb b/lib/solid_queue/processes/poller.rb index 75df61045..58ee200f5 100644 --- a/lib/solid_queue/processes/poller.rb +++ b/lib/solid_queue/processes/poller.rb @@ -43,11 +43,7 @@ def poll def with_polling_volume SolidQueue.instrument(:polling) do - if SolidQueue.silence_polling? && ActiveRecord::Base.logger - ActiveRecord::Base.logger.silence { yield } - else - yield - end + with_silenced_queries { yield } end end end diff --git a/lib/solid_queue/processes/registrable.rb b/lib/solid_queue/processes/registrable.rb index 35b4e01bd..e40413b00 100644 --- a/lib/solid_queue/processes/registrable.rb +++ b/lib/solid_queue/processes/registrable.rb @@ -39,7 +39,7 @@ def registered? def launch_heartbeat @heartbeat_task = Concurrent::TimerTask.new(execution_interval: SolidQueue.process_heartbeat_interval) do - wrap_in_app_executor { heartbeat } + wrap_in_app_executor { with_silenced_queries { heartbeat } } end @heartbeat_task.add_observer do |_, _, error| @@ -61,7 +61,7 @@ def heartbeat end def reload_metadata - wrap_in_app_executor { process&.update(metadata: metadata.compact) } + wrap_in_app_executor { with_silenced_queries { process&.update(metadata: metadata.compact) } } end end end diff --git a/lib/solid_queue/scheduler/recurring_schedule.rb b/lib/solid_queue/scheduler/recurring_schedule.rb index a1e2409e0..f538e3e81 100644 --- a/lib/solid_queue/scheduler/recurring_schedule.rb +++ b/lib/solid_queue/scheduler/recurring_schedule.rb @@ -48,9 +48,11 @@ def task_keys def reschedule_dynamic_tasks wrap_in_app_executor do - reload_dynamic_tasks - schedule_created_dynamic_tasks - unschedule_deleted_dynamic_tasks + with_silenced_queries do + reload_dynamic_tasks + schedule_created_dynamic_tasks + unschedule_deleted_dynamic_tasks + end end end diff --git a/lib/solid_queue/supervisor/maintenance.rb b/lib/solid_queue/supervisor/maintenance.rb index d92569d58..2c29e6b56 100644 --- a/lib/solid_queue/supervisor/maintenance.rb +++ b/lib/solid_queue/supervisor/maintenance.rb @@ -24,7 +24,7 @@ def stop_maintenance_task end def prune_dead_processes - wrap_in_app_executor { SolidQueue::Process.prune(excluding: process) } + wrap_in_app_executor { with_silenced_queries { SolidQueue::Process.prune(excluding: process) } } end def fail_orphaned_executions diff --git a/test/unit/dispatcher_test.rb b/test/unit/dispatcher_test.rb index 7df0591f5..a5f0f49a9 100644 --- a/test/unit/dispatcher_test.rb +++ b/test/unit/dispatcher_test.rb @@ -39,7 +39,7 @@ class DispatcherTest < ActiveSupport::TestCase test "polling queries are logged" do log = StringIO.new with_active_record_logger(ActiveSupport::Logger.new(log)) do - with_polling(silence: false) do + with_silence_queries(false) do rewind_io(log) @dispatcher.start sleep 0.5.second @@ -52,7 +52,7 @@ class DispatcherTest < ActiveSupport::TestCase test "polling queries can be silenced" do log = StringIO.new with_active_record_logger(ActiveSupport::Logger.new(log)) do - with_polling(silence: true) do + with_silence_queries(true) do rewind_io(log) @dispatcher.start sleep 0.5.second @@ -62,9 +62,9 @@ class DispatcherTest < ActiveSupport::TestCase assert_no_match /SELECT .* FROM .solid_queue_scheduled_executions. WHERE/, log.string end - test "silencing polling queries when there's no Active Record logger" do + test "silencing queries when there's no Active Record logger" do with_active_record_logger(nil) do - with_polling(silence: true) do + with_silence_queries(true) do @dispatcher.start sleep 0.5.second end @@ -131,11 +131,11 @@ class DispatcherTest < ActiveSupport::TestCase end private - def with_polling(silence:) - old_silence_polling, SolidQueue.silence_polling = SolidQueue.silence_polling, silence + def with_silence_queries(silence) + old_silence_queries, SolidQueue.silence_queries = SolidQueue.silence_queries, silence yield ensure - SolidQueue.silence_polling = old_silence_polling + SolidQueue.silence_queries = old_silence_queries end def with_active_record_logger(logger) diff --git a/test/unit/worker_test.rb b/test/unit/worker_test.rb index 3d692404b..7c6debbbb 100644 --- a/test/unit/worker_test.rb +++ b/test/unit/worker_test.rb @@ -106,7 +106,7 @@ class WorkerTest < ActiveSupport::TestCase test "polling queries are logged" do log = StringIO.new with_active_record_logger(ActiveSupport::Logger.new(log)) do - with_polling(silence: false) do + with_silence_queries(false) do @worker.start sleep 0.2 end @@ -118,7 +118,7 @@ class WorkerTest < ActiveSupport::TestCase test "polling queries can be silenced" do log = StringIO.new with_active_record_logger(ActiveSupport::Logger.new(log)) do - with_polling(silence: true) do + with_silence_queries(true) do @worker.start sleep 0.2 end @@ -127,9 +127,9 @@ class WorkerTest < ActiveSupport::TestCase assert_no_match /SELECT .* FROM .solid_queue_ready_executions. WHERE .solid_queue_ready_executions...queue_name./, log.string end - test "silencing polling queries when there's no Active Record logger" do + test "silencing queries when there's no Active Record logger" do with_active_record_logger(nil) do - with_polling(silence: true) do + with_silence_queries(true) do @worker.start sleep 0.2 end @@ -140,6 +140,54 @@ class WorkerTest < ActiveSupport::TestCase assert_no_registered_processes end + test "heartbeat queries can be silenced" do + old_heartbeat_interval, SolidQueue.process_heartbeat_interval = SolidQueue.process_heartbeat_interval, 0.2.second + + log = StringIO.new + with_active_record_logger(ActiveSupport::Logger.new(log)) do + with_silence_queries(true) do + @worker.start + wait_for_registered_processes(1, timeout: 1.second) + sleep 0.5 + end + end + + assert_no_match /UPDATE .solid_queue_processes. SET .+last_heartbeat_at/, log.string + ensure + SolidQueue.process_heartbeat_interval = old_heartbeat_interval + end + + test "heartbeat queries are logged when silence_queries is false" do + old_heartbeat_interval, SolidQueue.process_heartbeat_interval = SolidQueue.process_heartbeat_interval, 0.2.second + + log = StringIO.new + with_active_record_logger(ActiveSupport::Logger.new(log)) do + with_silence_queries(false) do + @worker.start + wait_for_registered_processes(1, timeout: 1.second) + sleep 0.5 + end + end + + assert_match /UPDATE .solid_queue_processes. SET .+last_heartbeat_at/, log.string + ensure + SolidQueue.process_heartbeat_interval = old_heartbeat_interval + end + + test "silence_polling is backward compatible with silence_queries" do + old_value = SolidQueue.silence_queries + + SolidQueue.silence_polling = false + assert_not SolidQueue.silence_queries? + assert_not SolidQueue.silence_polling? + + SolidQueue.silence_polling = true + assert SolidQueue.silence_queries? + assert SolidQueue.silence_polling? + ensure + SolidQueue.silence_queries = old_value + end + test "run inline" do worker = SolidQueue::Worker.new(queues: "*", threads: 3, polling_interval: 0.2) worker.mode = :inline @@ -195,11 +243,11 @@ class WorkerTest < ActiveSupport::TestCase end private - def with_polling(silence:) - old_silence_polling, SolidQueue.silence_polling = SolidQueue.silence_polling, silence + def with_silence_queries(silence) + old_silence_queries, SolidQueue.silence_queries = SolidQueue.silence_queries, silence yield ensure - SolidQueue.silence_polling = old_silence_polling + SolidQueue.silence_queries = old_silence_queries end def with_active_record_logger(logger)