diff --git a/lib/cloud_controller/process_observer.rb b/lib/cloud_controller/process_observer.rb index f70e4ee1a67..39bd249cc18 100644 --- a/lib/cloud_controller/process_observer.rb +++ b/lib/cloud_controller/process_observer.rb @@ -37,11 +37,15 @@ def react_to_state_change(process) process.update(revision: process.app.latest_revision) if process.revisions_enabled? - @runners.runner_for_process(process).start unless process.needs_staging? + # Reload to get the DB-assigned updated_at, which ProcessesSync compares against + # the LRP annotation to detect drift. Without this, the stale in-memory value + # causes an unnecessary re-sync. + @runners.runner_for_process(process.reload).start unless process.needs_staging? end def react_to_instances_change(process) - @runners.runner_for_process(process).scale if process.started? && process.active? + # Same as above: reload to get the DB-assigned updated_at before building the LRP annotation. + @runners.runner_for_process(process.reload).scale if process.started? && process.active? end def with_diego_communication_handling diff --git a/spec/unit/lib/cloud_controller/process_observer_spec.rb b/spec/unit/lib/cloud_controller/process_observer_spec.rb index 08e4211aadd..ab3dfe96355 100644 --- a/spec/unit/lib/cloud_controller/process_observer_spec.rb +++ b/spec/unit/lib/cloud_controller/process_observer_spec.rb @@ -5,7 +5,7 @@ module VCAP::CloudController let(:stagers) { double(:stagers, stager_for_build: stager) } let(:runners) { instance_double(Runners, runner_for_process: runner) } let(:stager) { double(:stager) } - let(:runner) { instance_double(Diego::Runner, stop: nil, start: nil) } + let(:runner) { instance_double(Diego::Runner, stop: nil, start: nil, scale: nil) } let(:process_active) { true } let(:diego) { false } let(:process) do @@ -33,6 +33,7 @@ module VCAP::CloudController before do ProcessObserver.configure(stagers, runners) + allow(process).to receive(:reload).and_return(process) end describe '.deleted' do @@ -312,6 +313,35 @@ module VCAP::CloudController end end end + + context 'updated_at annotation accuracy' do + let(:received) { [] } + + before do + allow(runners).to receive(:runner_for_process) do |p| + received << p.updated_at + runner + end + end + + context 'when the process instances have changed' do + it 'passes a process with the correct updated_at timestamp to the runner', isolation: :truncation do + process_model = ProcessModelFactory.make(state: 'STARTED') + process_model.update(instances: process_model.instances + 1) + + expect(received.last).to eq(process_model.reload.updated_at) + end + end + + context 'when the process state has changed' do + it 'passes a process with the correct updated_at timestamp to the runner', isolation: :truncation do + process_model = ProcessModelFactory.make(state: 'STOPPED') + process_model.update(state: ProcessModel::STARTED) + + expect(received.last).to eq(process_model.reload.updated_at) + end + end + end end end end diff --git a/spec/unit/models/runtime/process_model_spec.rb b/spec/unit/models/runtime/process_model_spec.rb index 565e7548fd4..90ad854969b 100644 --- a/spec/unit/models/runtime/process_model_spec.rb +++ b/spec/unit/models/runtime/process_model_spec.rb @@ -1495,7 +1495,7 @@ def act_as_cf_admin end describe 'saving' do - it 'calls AppObserver.updated', isolation: :truncation do + it 'calls ProcessObserver.updated', isolation: :truncation do process = ProcessModelFactory.make expect(ProcessObserver).to receive(:updated).with(process) process.update(instances: process.instances + 1)