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))
Esempio n. 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

    # 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
    def test_probably_has_capacity_get_queues(self):
        d = {u'pool': [u'default'], u'os': [u'Ubuntu-16.04']}
        # Capacity registers there only once there's a request enqueued and
        # get_queues() is called.
        _assert_bot()
        request = _gen_request(properties=_gen_properties(dimensions=d))
        task_queues.assert_task_async(request).get_result()
        self.assertEqual(1, self.execute_tasks())
        self.assertEqual(None, task_queues.probably_has_capacity(d))

        # It get sets only once get_queues() is called.
        bot_root_key = bot_management.get_root_key(u'bot1')
        task_queues.get_queues(bot_root_key)
        self.assertEqual(True, task_queues.probably_has_capacity(d))
        self.assertEqual([1843498234],
                         memcache.get('bot1', namespace='task_queues'))
 def test_probably_has_capacity(self):
     d = {u'pool': [u'default'], u'os': [u'Ubuntu-16.04']}
     # A bot coming online doesn't register capacity automatically.
     _assert_bot()
     self.assertEqual([], memcache.get('bot1', namespace='task_queues'))
     self.assertEqual(1, bot_management.BotInfo.query().count())
     self.assertEqual(None, task_queues.probably_has_capacity(d))
Esempio n. 5
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_probably_has_capacity_empty(self):
     # The bot can service this dimensions.
     d = {u'pool': [u'default'], u'os': [u'Ubuntu-16.04']}
     # By default, nothing has capacity.
     self.assertEqual(None, task_queues.probably_has_capacity(d))
     self.assertEqual(None, memcache.get('bot1', namespace='task_queues'))
Esempio n. 7
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))