Skip to content

Commit f75dd73

Browse files
authored
Properly shut down Concurrent::TimerTasks when Puma is stopped (#4681)
* Properly shut down Concurrent::TimerTasks when Puma is stopped * Spec for PeriodicUpdater.stop_updates
1 parent b4a64e3 commit f75dd73

File tree

4 files changed

+48
-11
lines changed

4 files changed

+48
-11
lines changed

lib/cloud_controller/metrics/periodic_updater.rb

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,23 @@ def initialize(start_time, log_counter, logger, statsd_updater, prometheus_updat
1616

1717
def setup_updates
1818
update!
19-
Concurrent::TimerTask.new(execution_interval: 600) { catch_error { update_user_count } }.execute
20-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_job_queue_length } }.execute
21-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_job_queue_load } }.execute
22-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_failed_job_count } }.execute
23-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_vitals } }.execute
24-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_log_counts } }.execute
25-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_task_stats } }.execute
26-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_deploying_count } }.execute
27-
Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_webserver_stats } }.execute
19+
@update_tasks = []
20+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 600) { catch_error { update_user_count } }
21+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_job_queue_length } }
22+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_job_queue_load } }
23+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_failed_job_count } }
24+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_vitals } }
25+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_log_counts } }
26+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_task_stats } }
27+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_deploying_count } }
28+
@update_tasks << Concurrent::TimerTask.new(execution_interval: 30) { catch_error { update_webserver_stats } }
29+
@update_tasks.each(&:execute)
30+
end
31+
32+
def stop_updates
33+
return unless @update_tasks
34+
35+
@update_tasks.each(&:shutdown)
2836
end
2937

3038
def update!

lib/cloud_controller/runners/puma_runner.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
module VCAP::CloudController
77
class PumaRunner
88
def initialize(config, app, logger, periodic_updater, request_logs)
9+
@periodic_updater = periodic_updater
910
@logger = logger
1011

1112
ENV['WEB_CONCURRENCY'] = 'auto' if config.get(:puma, :automatic_worker_count)
@@ -59,8 +60,12 @@ def initialize(config, app, logger, periodic_updater, request_logs)
5960
events = Puma::Events.new
6061
events.after_booted do
6162
prometheus_updater.update_gauge_metric(:cc_db_connection_pool_timeouts_total, 0, labels: { process_type: 'main' })
62-
periodic_updater.setup_updates
63+
@periodic_updater.setup_updates
6364
end
65+
events.after_stopped do
66+
@periodic_updater.stop_updates unless @periodic_updater.nil?
67+
end
68+
6469
@puma_launcher = Puma::Launcher.new(puma_config, log_writer:, events:)
6570
end
6671

spec/unit/lib/cloud_controller/metrics/periodic_updater_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,28 @@ module VCAP::CloudController::Metrics
183183
@periodic_timers[6][:block].call
184184
end
185185
end
186+
187+
context 'when PeriodicUpdater is shut down' do
188+
it 'does nothing when updates have not been setup' do
189+
expect { periodic_updater.stop_updates }.not_to raise_error
190+
end
191+
192+
it 'shuts down all timer tasks after setup_updates' do
193+
timer_doubles = []
194+
allow(Concurrent::TimerTask).to receive(:new) do |*|
195+
dbl = double('TimerTask', execute: nil, shutdown: nil)
196+
timer_doubles << dbl
197+
dbl
198+
end
199+
200+
periodic_updater.setup_updates
201+
202+
expect(timer_doubles.size).to eq(9)
203+
expect(timer_doubles).to all(receive(:shutdown).once)
204+
205+
periodic_updater.stop_updates
206+
end
207+
end
186208
end
187209

188210
describe '#update_deploying_count' do

spec/unit/lib/cloud_controller/runners/puma_runner_spec.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ module VCAP::CloudController
204204
end
205205

206206
describe 'after_stopped' do
207-
it 'stops EM and logs incomplete requests' do
207+
it 'stops the TimerTasks and logs incomplete requests' do
208+
expect(periodic_updater).to receive(:stop_updates)
209+
208210
puma_launcher.events.fire(:after_stopped)
209211
end
210212
end

0 commit comments

Comments
 (0)