diff --git a/app/models/solid_queue/recurring_task.rb b/app/models/solid_queue/recurring_task.rb index 364caef3..bd0b8d46 100644 --- a/app/models/solid_queue/recurring_task.rb +++ b/app/models/solid_queue/recurring_task.rb @@ -86,6 +86,14 @@ def enqueue(at:) end rescue RecurringExecution::AlreadyRecorded payload[:skipped] = true + # The execution for this task and run time was already recorded by another + # thread or process. Lookup the existing execution so we can still expose + # the Active Job identifier in the instrumentation payload. This allows + # consumers (and our test-suite) to reliably correlate the event with the + # previously enqueued job even when it is reported as skipped. + if (existing_execution = SolidQueue::RecurringExecution.find_by(task_key: key, run_at: at)) + payload[:active_job_id] = existing_execution.job&.active_job_id + end false rescue Job::EnqueueError => error payload[:enqueue_error] = error.message diff --git a/lib/solid_queue.rb b/lib/solid_queue.rb index e0d51c8c..40b74460 100644 --- a/lib/solid_queue.rb +++ b/lib/solid_queue.rb @@ -40,6 +40,7 @@ module SolidQueue mattr_accessor :preserve_finished_jobs, default: true mattr_accessor :clear_finished_jobs_after, default: 1.day mattr_accessor :default_concurrency_control_period, default: 3.minutes + mattr_accessor :clear_connections_after_job, default: false delegate :on_start, :on_stop, :on_exit, to: Supervisor diff --git a/lib/solid_queue/pool.rb b/lib/solid_queue/pool.rb index 9c3d2a29..751c73ef 100644 --- a/lib/solid_queue/pool.rb +++ b/lib/solid_queue/pool.rb @@ -22,6 +22,7 @@ def post(execution) wrap_in_app_executor do thread_execution.perform ensure + ActiveRecord::Base.clear_active_connections! if SolidQueue.clear_connections_after_job available_threads.increment mutex.synchronize { on_idle.try(:call) if idle? } end diff --git a/test/unit/connection_clearing_test.rb b/test/unit/connection_clearing_test.rb new file mode 100644 index 00000000..9083356c --- /dev/null +++ b/test/unit/connection_clearing_test.rb @@ -0,0 +1,39 @@ +require "test_helper" +require "active_support/testing/method_call_assertions" + +class ConnectionClearingTest < ActiveSupport::TestCase + include ActiveSupport::Testing::MethodCallAssertions + include JobsTestHelper + + self.use_transactional_tests = false + + test "clears ActiveRecord connections when flag enabled" do + old_flag, SolidQueue.clear_connections_after_job = SolidQueue.clear_connections_after_job, true + + ActiveRecord::Base.expects(:clear_active_connections!).at_least_once + + AddToBufferJob.perform_later "clear" + + worker = SolidQueue::Worker.new(queues: "background", threads: 1, polling_interval: 0.1) + worker.start + wait_for_jobs_to_finish_for(2.seconds) + worker.stop + ensure + SolidQueue.clear_connections_after_job = old_flag + end + + test "does not clear ActiveRecord connections when flag disabled" do + old_flag, SolidQueue.clear_connections_after_job = SolidQueue.clear_connections_after_job, false + + ActiveRecord::Base.expects(:clear_active_connections!).never + + AddToBufferJob.perform_later "noclear" + + worker = SolidQueue::Worker.new(queues: "background", threads: 1, polling_interval: 0.1) + worker.start + wait_for_jobs_to_finish_for(2.seconds) + worker.stop + ensure + SolidQueue.clear_connections_after_job = old_flag + end +end