Beispiel #1
0
def has_capacity(dimensions):
    """Returns True if there's a reasonable chance for this task request
  dimensions set to be serviced by a bot alive.

  First look at the task queues, then look into the datastore to figure this
  out.
  """
    assert not ndb.in_transaction()
    # Look at the fast path.
    cap = task_queues.probably_has_capacity(dimensions)
    if cap is not None:
        return cap

    # Do a query. That's slower and it's eventually consistent.
    q = BotInfo.query()
    flat = task_queues.dimensions_to_flat(dimensions)
    for f in flat:
        q = q.filter(BotInfo.dimensions_flat == f)
    if q.count(limit=1):
        logging.info('Found capacity via BotInfo: %s', flat)
        # Add it to the quick cache to improve performance.
        task_queues.set_has_capacity(dimensions)
        return True

    logging.error('HAS NO CAPACITY: %s', flat)
    # TODO(maruel): https://crbug.com/839173
    return _FAKE_CAPACITY
Beispiel #2
0
def has_capacity(dimensions):
    """Returns True if there's a reasonable chance for this task request
  dimensions set to be serviced by a bot alive.

  First look at the task queues, then look into the datastore to figure this
  out.
  """
    assert not ndb.in_transaction()
    # Look at the fast path.
    cap = task_queues.probably_has_capacity(dimensions)
    if cap is not None:
        return cap

    # Add it to the 'quick cache' to improve performance. This cache is kept for
    # the same duration as how long bots are considered still alive without a
    # ping. Useful if there's a single bot in the fleet for these dimensions and
    # it takes a long time to reboot. This is the case with Android with slow
    # initialization and some baremetal bots (thanks SCSI firmware!).
    seconds = config.settings().bot_death_timeout_secs

    @ndb.tasklet
    def run_query(flat):
        # Do a query. That's slower and it's eventually consistent.
        q = BotInfo.query()
        for f in flat:
            q = q.filter(BotInfo.dimensions_flat == f)

        num = yield q.count_async(limit=1)
        if num:
            logging.info('Found capacity via BotInfo: %s', flat)
            raise ndb.Return(True)

        # Search a bit harder. In this case, we're looking for BotEvent which would
        # be a bot that used to exist recently.
        cutoff = utils.utcnow() - datetime.timedelta(seconds=seconds)
        q = BotEvent.query(BotEvent.ts > cutoff)
        for f in flat:
            q = q.filter(BotEvent.dimensions_flat == f)
        num = yield q.count_async(limit=1)
        if num:
            logging.info('Found capacity via BotEvent: %s', flat)
            raise ndb.Return(True)
        raise ndb.Return(False)

    futures = [
        run_query(f)
        for f in task_queues.expand_dimensions_to_flats(dimensions)
    ]

    ndb.tasklets.Future.wait_all(futures)
    if any(f.get_result() for f in futures):
        task_queues.set_has_capacity(dimensions, seconds)
        return True

    logging.warning('HAS NO CAPACITY: %s', dimensions)
    return False
 def test_set_has_capacity(self):
     d = {u'pool': [u'default'], u'os': [u'Ubuntu-16.04']}
     # By default, nothing has capacity. None means no data.
     now = utils.utcnow()
     self.mock_now(now, 0)
     self.assertEqual(None, task_queues.probably_has_capacity(d))
     # Keep the value for 2 seconds, exclusive.
     task_queues.set_has_capacity(d, 2)
     self.assertEqual(True, task_queues.probably_has_capacity(d))
     self.mock_now(now, 1)
     self.assertEqual(True, task_queues.probably_has_capacity(d))
     # The value expired.
     self.mock_now(now, 2)
     self.assertEqual(None, task_queues.probably_has_capacity(d))
Beispiel #4
0
 def test_set_has_capacity(self):
   d = {u'pool': [u'default'], u'os': [u'Ubuntu-16.04']}
   # By default, nothing has capacity. None means no data.
   self.assertEqual(None, task_queues.probably_has_capacity(d))
   task_queues.set_has_capacity(d)
   self.assertEqual(True, task_queues.probably_has_capacity(d))