Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import itertools | |
| 5 from datetime import datetime | 6 from datetime import datetime |
| 6 | 7 |
| 7 from twisted.python import log | 8 from twisted.python import log |
| 8 from twisted.internet import reactor | 9 from twisted.internet import reactor |
| 9 | 10 |
| 10 | 11 |
| 11 class FloatingSet(object): | 12 class FloatingSet(object): |
| 12 """A set describing available primary/floating slaves.""" | 13 """A set describing available primary/floating slaves.""" |
| 13 def __init__(self): | 14 def __init__(self): |
| 14 self._primary = set() | 15 self._primary = set() |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 Args: | 87 Args: |
| 87 fs (FloatingSet): The set of available primary/floating slaves. | 88 fs (FloatingSet): The set of available primary/floating slaves. |
| 88 grace_period: (timedelta) The amount of time that a slave can be offline | 89 grace_period: (timedelta) The amount of time that a slave can be offline |
| 89 before builds fall through to a lower strata. | 90 before builds fall through to a lower strata. |
| 90 """ | 91 """ |
| 91 | 92 |
| 92 def __init__(self, fs, grace_period): | 93 def __init__(self, fs, grace_period): |
| 93 self._primary, self._floating = fs.Get() | 94 self._primary, self._floating = fs.Get() |
| 94 self._fs = fs | 95 self._fs = fs |
| 95 self._grace_period = grace_period | 96 self._grace_period = grace_period |
| 96 self._slave_seen_times = {} | |
| 97 self._poke_builder_timers = {} | 97 self._poke_builder_timers = {} |
| 98 self.verbose = False | 98 self.verbose = False |
| 99 | 99 |
| 100 started = _get_now() | |
| 101 self._slave_seen_times = dict((s, started) for s in itertools.chain( | |
| 102 self._primary, self._floating)) | |
| 103 | |
| 100 def __repr__(self): | 104 def __repr__(self): |
| 101 return '%s(%s)' % (type(self).__name__, self._fs) | 105 return '%s(%s)' % (type(self).__name__, self._fs) |
| 102 | 106 |
| 103 def __call__(self, builder, slave_builders): | 107 def __call__(self, builder, slave_builders): |
| 104 """Main 'nextSlave' invocation point. | 108 """Main 'nextSlave' invocation point. |
| 105 | 109 |
| 106 When this is called, we are given the following information: | 110 When this is called, we are given the following information: |
| 107 - The Builder | 111 - The Builder |
| 108 - A set of 'SlaveBuilder' instances that are available and ready for | 112 - A set of 'SlaveBuilder' instances that are available and ready for |
| 109 assignment (slave_builders). | 113 assignment (slave_builders). |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 | 181 |
| 178 # Is this slave online? If so, we won't consider floating candiates. | 182 # Is this slave online? If so, we won't consider floating candiates. |
| 179 if slave_name in online_slave_builders: | 183 if slave_name in online_slave_builders: |
| 180 # The slave is online, but is not proposed (BUSY); add it to the | 184 # The slave is online, but is not proposed (BUSY); add it to the |
| 181 # desired slaves list. | 185 # desired slaves list. |
| 182 self._debug('Slave [%s] is online but BUSY.', slave_name) | 186 self._debug('Slave [%s] is online but BUSY.', slave_name) |
| 183 within_grace_period.append(slave_name) | 187 within_grace_period.append(slave_name) |
| 184 some_primary_were_busy = True | 188 some_primary_were_busy = True |
| 185 continue | 189 continue |
| 186 | 190 |
| 191 # The slave is offline. Is this slave within the grace period? | |
| 192 # | |
|
bpastene
2016/08/17 01:22:13
nit: remove line
dnj
2016/08/17 01:24:17
Done.
| |
| 187 # Get the 'SlaveStatus' object for this slave | 193 # Get the 'SlaveStatus' object for this slave |
| 188 slave_status = slave_status_map.get(slave_name) | 194 slave_status = slave_status_map.get(slave_name) |
| 189 if slave_status is None: | 195 last_seen = self._get_latest_seen_time(slave_name, slave_status) |
| 190 continue | |
| 191 | |
| 192 # The slave is offline. Is this slave within the grace period? | |
| 193 last_seen = self._get_latest_seen_time(slave_status) | |
| 194 if last_seen < grace_threshold: | 196 if last_seen < grace_threshold: |
| 195 # No, the slave is older than our grace period. | 197 # No, the slave is older than our grace period. |
| 196 self._debug('Slave [%s] is OFFLINE and outside grace period ' | 198 self._debug('Slave [%s] is OFFLINE and outside grace period ' |
| 197 '(%s < %s).', slave_name, last_seen, grace_threshold) | 199 '(%s < %s).', slave_name, last_seen, grace_threshold) |
| 198 continue | 200 continue |
| 199 | 201 |
| 200 # This slave is within its grace threshold. Add it to the list of | 202 # This slave is within its grace threshold. Add it to the list of |
| 201 # desired slaves from this set and update our wait delta in case we | 203 # desired slaves from this set and update our wait delta in case we |
| 202 # have to poke. | 204 # have to poke. |
| 203 # | 205 # |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 247 @staticmethod | 249 @staticmethod |
| 248 def _get_all_slave_status(builder): | 250 def _get_all_slave_status(builder): |
| 249 # Try using the builder's BuilderStatus object to get a list of all slaves | 251 # Try using the builder's BuilderStatus object to get a list of all slaves |
| 250 if builder.builder_status is not None: | 252 if builder.builder_status is not None: |
| 251 return builder.builder_status.getSlaves() | 253 return builder.builder_status.getSlaves() |
| 252 | 254 |
| 253 # Satisfy with the list of currently-connected slaves | 255 # Satisfy with the list of currently-connected slaves |
| 254 return [slave_builder.slave.slave_status | 256 return [slave_builder.slave.slave_status |
| 255 for slave_builder in builder.slaves] | 257 for slave_builder in builder.slaves] |
| 256 | 258 |
| 257 def _get_latest_seen_time(self, slave_status): | 259 def _get_latest_seen_time(self, slave_name, slave_status): |
| 258 times = [] | 260 times = [self._slave_seen_times[slave_name]] |
| 259 | 261 |
| 260 # Add all of the registered connect times | 262 if slave_status: |
| 261 times += [datetime.fromtimestamp(connect_time) | 263 # Add all of the registered connect times |
| 262 for connect_time in slave_status.connect_times] | 264 times += [datetime.fromtimestamp(connect_time) |
| 265 for connect_time in slave_status.connect_times] | |
| 263 | 266 |
| 264 # Add the time of the slave's last message | 267 # Add the time of the slave's last message |
| 265 times.append(datetime.fromtimestamp(slave_status.lastMessageReceived())) | 268 times.append(datetime.fromtimestamp(slave_status.lastMessageReceived())) |
| 266 | |
| 267 # Add the last time we've seen the slave in our 'nextSlave' function | |
| 268 last_seen_time = self._slave_seen_times.get(slave_status.name) | |
| 269 if last_seen_time is not None: | |
| 270 times.append(last_seen_time) | |
| 271 | 269 |
| 272 if not times: | 270 if not times: |
|
bpastene
2016/08/17 01:22:13
OOC, would times ever be empty here? If I'm readin
dnj
2016/08/17 01:24:17
Oh yeah that's not needed anymore.
| |
| 273 return None | 271 return None |
| 274 return max(times) | 272 return max(times) |
| 275 | 273 |
| 276 def _record_slave_seen_time(self, build_slave, now): | 274 def _record_slave_seen_time(self, build_slave, now): |
| 277 self._slave_seen_times[build_slave.slavename] = now | 275 self._slave_seen_times[build_slave.slavename] = now |
| 278 | 276 |
| 279 def _schedule_builder_timer(self, builder, delta): | 277 def _schedule_builder_timer(self, builder, delta): |
| 280 poke_builder_timer = self._poke_builder_timers.get(builder.name) | 278 poke_builder_timer = self._poke_builder_timers.get(builder.name) |
| 281 if poke_builder_timer is None: | 279 if poke_builder_timer is None: |
| 282 poke_builder_timer = PokeBuilderTimer( | 280 poke_builder_timer = PokeBuilderTimer( |
| 283 builder.botmaster, | 281 builder.botmaster, |
| 284 builder.name, | 282 builder.name, |
| 285 ) | 283 ) |
| 286 self._poke_builder_timers[builder.name] = poke_builder_timer | 284 self._poke_builder_timers[builder.name] = poke_builder_timer |
| 287 poke_builder_timer.reset(delta) | 285 poke_builder_timer.reset(delta) |
| 288 | 286 |
| 289 def _cancel_builder_timer(self, builder): | 287 def _cancel_builder_timer(self, builder): |
| 290 poke_builder_timer = self._poke_builder_timers.get(builder.name) | 288 poke_builder_timer = self._poke_builder_timers.get(builder.name) |
| 291 if poke_builder_timer is None: | 289 if poke_builder_timer is None: |
| 292 return | 290 return |
| 293 poke_builder_timer.cancel() | 291 poke_builder_timer.cancel() |
| 294 | 292 |
| 295 | 293 |
| 296 def _get_now(): | 294 def _get_now(): |
| 297 """Returns (datetime.datetime): The current time. | 295 """Returns (datetime.datetime): The current time. |
| 298 | 296 |
| 299 This exists so it can be overridden by mocks in unit tests. | 297 This exists so it can be overridden by mocks in unit tests. |
| 300 """ | 298 """ |
| 301 return datetime.now() | 299 return datetime.now() |
| OLD | NEW |