11require 'cloud_controller/deployment_updater/actions/scale_down_canceled_processes'
2- require 'cloud_controller/deployment_updater/actions/scale_down_old_process'
32require 'cloud_controller/deployment_updater/actions/finalize'
3+ require 'cloud_controller/deployment_updater/actions/down_scaler'
4+ require 'cloud_controller/deployment_updater/actions/up_scaler'
45require 'cloud_controller/diego/constants'
56
67module VCAP ::CloudController
78 module DeploymentUpdater
89 module Actions
910 class Scale
10- HEALTHY_STATES = [ VCAP ::CloudController ::Diego ::LRP_RUNNING , VCAP ::CloudController ::Diego ::LRP_STARTING ] . freeze
1111 attr_reader :deployment , :logger , :app , :target_total_instance_count , :interim_desired_instance_count
1212
13- def initialize ( deployment , logger , target_total_instance_count , interim_desired_instance_count = nil )
13+ def initialize ( deployment , logger , target_total_instance_count , interim_desired_instance_count = nil )
1414 @deployment = deployment
1515 @logger = logger
1616 @app = deployment . app
@@ -19,110 +19,52 @@ def initialize(deployment, logger, target_total_instance_count, interim_desired_
1919 end
2020
2121 def call
22+ down_scaler = DownScaler . new ( deployment , logger , target_total_instance_count , instance_count_summary . routable_instances_count )
23+ up_scaler = UpScaler . new ( deployment , logger , interim_desired_instance_count , instance_count_summary )
24+
2225 deployment . db . transaction do
2326 return unless deployment . lock! . state == DeploymentModel ::DEPLOYING_STATE
24-
25- return unless can_scale? || can_downscale?
27+ return unless up_scaler . can_scale? || down_scaler . can_downscale?
2628
2729 app . lock!
2830
2931 oldest_web_process_with_instances . lock!
3032 deploying_web_process . lock!
3133
3234 deployment . update (
33- state : DeploymentModel ::DEPLOYING_STATE ,
3435 status_value : DeploymentModel ::ACTIVE_STATUS_VALUE ,
3536 status_reason : DeploymentModel ::DEPLOYING_STATUS_REASON
3637 )
37-
38- ScaleDownCanceledProcesses . new ( deployment ) . call
39-
40- scale_down_old_processes if can_downscale?
41-
42- return true if deploying_web_process . instances >= interim_desired_instance_count
43-
44- if can_scale?
45- deploying_web_process . update ( instances : desired_new_instances )
46- deployment . update ( last_healthy_at : Time . now )
47- end
48- end
49- false
50- end
51-
52- private
5338
54- def scale_down_old_processes
55- instances_to_reduce = non_deploying_web_processes . map ( &:instances ) . sum - desired_non_deploying_instances
39+ ScaleDownCanceledProcesses . new ( deployment ) . call
5640
57- return if instances_to_reduce <= 0
41+ down_scaler . scale_down if down_scaler . can_downscale?
5842
59- non_deploying_web_processes . each do |process |
60- if instances_to_reduce < process . instances
61- ScaleDownOldProcess . new ( deployment , process , process . instances - instances_to_reduce ) . call
62- break
63- end
43+ return true if up_scaler . finished_scaling?
6444
65- instances_to_reduce -= process . instances
66- ScaleDownOldProcess . new ( deployment , process , 0 ) . call
45+ up_scaler . scale_up if up_scaler . can_scale?
6746 end
68- end
69-
70- def can_scale?
71- starting_instances . count < deployment . max_in_flight &&
72- unhealthy_instances . count == 0 &&
73- routable_instances . count >= deploying_web_process . instances - deployment . max_in_flight
74- rescue CloudController ::Errors ::ApiError # the instances_reporter re-raises InstancesUnavailable as ApiError
75- logger . info ( "skipping-deployment-update-for-#{ deployment . guid } " )
7647 false
77- end
78-
79- def can_downscale?
80- non_deploying_web_processes . map ( &:instances ) . sum > desired_non_deploying_instances
8148 rescue CloudController ::Errors ::ApiError # the instances_reporter re-raises InstancesUnavailable as ApiError
8249 logger . info ( "skipping-deployment-update-for-#{ deployment . guid } " )
8350 false
8451 end
8552
86- def desired_non_deploying_instances
87- [ target_total_instance_count - routable_instances . count , 0 ] . max
88- end
89-
90- def desired_new_instances
91- [ routable_instances . count + deployment . max_in_flight , interim_desired_instance_count ] . min
92- end
53+ private
9354
9455 def oldest_web_process_with_instances
56+ # TODO: lock all web processes? We might alter all of them, depending on max-in-flight size
9557 @oldest_web_process_with_instances ||= app . web_processes . select { |process | process . instances > 0 } . min_by { |p | [ p . created_at , p . id ] }
9658 end
9759
98- def non_deploying_web_processes
99- app . web_processes . reject { | process | process . guid == deploying_web_process . guid } . sort_by { | p | [ p . created_at , p . id ] }
60+ def instance_count_summary
61+ @instance_count_summary ||= instance_reporters . instance_count_summary ( deploying_web_process )
10062 end
10163
10264 def deploying_web_process
10365 @deploying_web_process ||= deployment . deploying_web_process
10466 end
10567
106- def starting_instances
107- healthy_instances . reject { |_ , val | val [ :state ] == VCAP ::CloudController ::Diego ::LRP_RUNNING && val [ :routable ] }
108- end
109-
110- def routable_instances
111- reported_instances . select { |_ , val | val [ :state ] == VCAP ::CloudController ::Diego ::LRP_RUNNING && val [ :routable ] }
112- end
113-
114- def healthy_instances
115- reported_instances . select { |_ , val | HEALTHY_STATES . include? ( val [ :state ] ) }
116- end
117-
118- def unhealthy_instances
119- reported_instances . reject { |_ , val | HEALTHY_STATES . include? ( val [ :state ] ) }
120- end
121-
122- def reported_instances
123- @reported_instances = instance_reporters . all_instances_for_app ( deploying_web_process )
124- end
125-
12668 def instance_reporters
12769 CloudController ::DependencyLocator . instance . instances_reporters
12870 end
0 commit comments