Skip to content

Commit cbc0999

Browse files
committed
Scale action takes total instance count from model rather than relying on original web process count
1 parent 0c1579a commit cbc0999

File tree

7 files changed

+76
-220
lines changed

7 files changed

+76
-220
lines changed

app/models/runtime/deployment_model.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ def current_canary_instance_target
118118
canary_step[:canary]
119119
end
120120

121+
def canary_total_instances
122+
canary_step[:canary] + canary_step[:original]
123+
end
124+
121125
def canary_step
122126
raise 'canary_step is only valid for canary deloyments' unless strategy == CANARY_STRATEGY
123127

@@ -135,6 +139,7 @@ def canary_step_plan
135139
target_canary = (original_web_process_instance_count * (weight.to_f / 100)).round.to_i
136140
target_canary = 1 if target_canary.zero?
137141
target_original = original_web_process_instance_count - target_canary + 1
142+
target_original = 0 if weight == 100
138143
{ canary: target_canary, original: target_original }
139144
end
140145
end

lib/cloud_controller/deployment_updater/actions/up_scaler.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def can_scale?
3131
end
3232

3333
def finished_scaling?
34-
deploying_web_process.instances >= interim_desired_instance_count
34+
deploying_web_process.instances >= interim_desired_instance_count && @routable_instances_count >= interim_desired_instance_count
3535
end
3636

3737
private

lib/cloud_controller/deployment_updater/updater.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def scale
2323
def canary
2424
with_error_logging('error-canarying-deployment') do
2525
# TODO: do we need to pass in deployment.original_web_process_instance_count + 1 if there is a single canary instance?
26-
finished = Actions::Scale.new(deployment, logger, deployment.original_web_process_instance_count, deployment.current_canary_instance_target).call
26+
finished = Actions::Scale.new(deployment, logger, deployment.canary_total_instances, deployment.current_canary_instance_target).call
2727
if finished
2828
deployment.update(
2929
last_healthy_at: Time.now,

spec/unit/lib/cloud_controller/deployment_updater/actions/canary_spec.rb

Lines changed: 0 additions & 201 deletions
This file was deleted.

spec/unit/lib/cloud_controller/deployment_updater/actions/up_scaler_spec.rb

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,30 +101,22 @@ module VCAP::CloudController
101101
expect(up_scaler.finished_scaling?).to be false
102102
end
103103

104-
# TODO: Currently, deployments transition to COMPLETED even if there are some instances that have not started and become routable
105-
# Since they can still fail at this stage, it might be better to wait for them to all become healthy and routable
106-
# before transitioning the deployment to completed
107-
108104
it 'returns false if number of routable instances does not match desired instances' do
109-
skip('Might need to restructure the scale action if we do this')
110105
summary = double(starting_instances_count: 0, routable_instances_count: 4, healthy_instances_count: 5, unhealthy_instances_count: 0)
111106
up_scaler = DeploymentUpdater::Actions::UpScaler.new(deployment, logger, 5, summary)
112107
expect(up_scaler.finished_scaling?).to be false
113108
end
114109

115-
it 'returns false if there are any unhealthy instances' do
116-
skip('Might need to restructure the scale action if we do this')
110+
it 'returns true if there are any unhealthy instances but we have already reached the target' do
117111
summary = double(starting_instances_count: 0, routable_instances_count: 5, healthy_instances_count: 5, unhealthy_instances_count: 1)
118-
up_scaler = DeploymentUpdater::Actions::UpScaler.new(deployment, logger, 10, summary)
119-
expect(up_scaler.finished_scaling?).to be false
112+
up_scaler = DeploymentUpdater::Actions::UpScaler.new(deployment, logger, 5, summary)
113+
expect(up_scaler.finished_scaling?).to be true
120114
end
121115

122-
it 'returns false if there are any starting instances' do
123-
skip('Might need to restructure the scale action if we do this')
124-
# TODO: perhaps this should return true? We have reached the target, after all...
116+
it 'returns true if there are any starting instances but we have already reached the target' do
125117
summary = double(starting_instances_count: 1, routable_instances_count: 5, healthy_instances_count: 5, unhealthy_instances_count: 0)
126-
up_scaler = DeploymentUpdater::Actions::UpScaler.new(deployment, logger, 10, summary)
127-
expect(up_scaler.finished_scaling?).to be false
118+
up_scaler = DeploymentUpdater::Actions::UpScaler.new(deployment, logger, 5, summary)
119+
expect(up_scaler.finished_scaling?).to be true
128120
end
129121
end
130122

spec/unit/lib/cloud_controller/deployment_updater/updater_spec.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ module VCAP::CloudController
192192

193193
context 'when the current step instance count has been reached' do
194194
let(:current_deploying_instances) { 5 }
195+
let(:current_web_instances) { 8 }
195196
let(:all_instances_results) do
196197
{
197198
0 => { state: 'RUNNING', uptime: 50, since: 2, routable: true },
@@ -205,6 +206,8 @@ module VCAP::CloudController
205206
it 'transitions state to paused' do
206207
subject.canary
207208
expect(deployment.state).to eq(DeploymentModel::PAUSED_STATE)
209+
expect(web_process.reload.instances).to eq(6)
210+
expect(deploying_web_process.instances).to eq(5)
208211
end
209212
end
210213

spec/unit/models/runtime/deployment_model_spec.rb

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,14 @@ module VCAP::CloudController
317317
{ canary: 1, original: 1 },
318318
{ canary: 1, original: 1 },
319319
{ canary: 1, original: 1 },
320-
{ canary: 1, original: 1 }
320+
{ canary: 1, original: 0 }
321321
]
322322
}
323323
]
324324

325325
tests.each do |test|
326326
context "with #{test[:existing_instances]} existing instances and weights #{test[:weights]}" do
327-
let(:canary_steps) { test[:weights].map { |weight| { :instance_weight => weight } } }
327+
let(:canary_steps) { test[:weights].map { |weight| { instance_weight: weight } } }
328328

329329
let(:deployment) do
330330
DeploymentModel.make(
@@ -361,6 +361,25 @@ module VCAP::CloudController
361361
end
362362
end
363363

364+
context 'when deployment is has a 100% step' do
365+
let(:deployment) do
366+
DeploymentModel.make(
367+
app: app,
368+
strategy: 'canary',
369+
droplet: droplet,
370+
deploying_web_process: deploying_web_process,
371+
canary_steps: [{ instance_weight: 1 }, { instance_weight: 25 }, { instance_weight: 50 }, { instance_weight: 99 }, { instance_weight: 100 }],
372+
original_web_process_instance_count: 10,
373+
canary_current_step: 1
374+
)
375+
end
376+
377+
it 'provides an extra canary instance for every step except at 100%' do
378+
expect(deployment.canary_step_plan).to eq([{ canary: 1, original: 10 }, { canary: 3, original: 8 }, { canary: 5, original: 6 }, { canary: 10, original: 1 },
379+
{ canary: 10, original: 0 }])
380+
end
381+
end
382+
364383
context 'when deployment is not canary' do
365384
let(:deployment) do
366385
DeploymentModel.make(
@@ -378,6 +397,44 @@ module VCAP::CloudController
378397
end
379398
end
380399

400+
describe '#current_canary_instance_target' do
401+
let(:deployment) do
402+
DeploymentModel.make(
403+
app: app,
404+
strategy: 'canary',
405+
droplet: droplet,
406+
deploying_web_process: deploying_web_process,
407+
canary_steps: [{ instance_weight: 1 }, { instance_weight: 25 }, { instance_weight: 50 }, { instance_weight: 99 }, { instance_weight: 100 }],
408+
original_web_process_instance_count: 10
409+
)
410+
end
411+
412+
it 'returns the canary target of the current step' do
413+
deployment.update(canary_current_step: 3)
414+
415+
expect(deployment.current_canary_instance_target).to eq(5)
416+
end
417+
end
418+
419+
describe '#canary_total_instances' do
420+
let(:deployment) do
421+
DeploymentModel.make(
422+
app: app,
423+
strategy: 'canary',
424+
droplet: droplet,
425+
deploying_web_process: deploying_web_process,
426+
canary_steps: [{ instance_weight: 1 }, { instance_weight: 25 }, { instance_weight: 50 }, { instance_weight: 99 }, { instance_weight: 100 }],
427+
original_web_process_instance_count: 10
428+
)
429+
end
430+
431+
it 'returns the total instances of the canary and original processes' do
432+
deployment.update(canary_current_step: 3)
433+
434+
expect(deployment.canary_total_instances).to eq(11)
435+
end
436+
end
437+
381438
describe '#canary_step' do
382439
let(:deployment) do
383440
DeploymentModel.make(
@@ -386,7 +443,7 @@ module VCAP::CloudController
386443
droplet: droplet,
387444
deploying_web_process: deploying_web_process,
388445
original_web_process_instance_count: 10,
389-
canary_steps: [{ :instance_weight => 20 }, { :instance_weight => 40 }],
446+
canary_steps: [{ instance_weight: 20 }, { instance_weight: 40 }],
390447
canary_current_step: 1
391448
)
392449
end

0 commit comments

Comments
 (0)