Match running instances to new assignments
Previously, the InstanceManager assumed that all "-1" assignment
entries meant that a new instance needed to be started. Now,
it checks all running instances that aren't explicitly assigned
(in terms of the scheduler specifying a port) and considers them
as having fulfilled the "-1" assignment.
@@ -547,8 +547,6 @@ class InstanceManager(object):
yield self._stop_app_instance(instance)
for version_key, assigned_ports in self._assignments.items():
- running_instances = [instance for instance in self._running_instances
- if instance.version_key == version_key]
try:
version = self._projects_manager.version_from_key(version_key)
except KeyError:
@@ -556,20 +554,34 @@ class InstanceManager(object):
# scheduler should remove any assignments for it.
continue
- # Stop instances that aren't assigned.
- for running_instance in running_instances:
- if running_instance.port not in assigned_ports:
+ # The number of required instances that don't have an assigned port.
+ new_assignment_count = sum(port == -1 for port in assigned_ports)
+
+ # Stop instances that aren't assigned. If the assignment list includes
+ # any -1s, match them to running instances that aren't in the assigned
+ # ports list.
+ candidates = [instance for instance in self._running_instances
+ if instance.version_key == version_key
+ and instance.port not in assigned_ports]
+ unmatched_instances = candidates[new_assignment_count:]
+ for running_instance in unmatched_instances:
logger.info('{} is no longer assigned'.format(running_instance))
yield self._stop_app_instance(running_instance)
- # Start assigned instances that aren't running.
+ # Start defined ports that aren't running.
+ running_ports = [instance.port for instance in self._running_instances
+ if instance.version_key == version_key]
for port in assigned_ports:
- if port == -1:
- port = self._get_lowest_port()
+ if port != -1 and port not in running_ports:
+ self._start_instance(version, port)
- instance = Instance(version.revision_key, port)
- if instance not in running_instances:
- self._start_instance(version, instance.port)
+ # Start new assignments that don't have a match.
+ candidates = [instance for instance in self._running_instances
+ if instance.version_key == version_key
+ and instance.port not in assigned_ports]
+ to_start = max(new_assignment_count - len(candidates), 0)
+ for _ in range(to_start):
+ self._start_instance(version, self._get_lowest_port())
@gen.coroutine
def _enforce_instance_details(self):
