The main run method of the client.

    This method does not normally return. Only if there have been more than
    connection_error_limit failures, the method returns and allows the
    client to exit.

def Run(self):
    """The main run method of the client.

    This method does not normally return. Only if there have been more than
    connection_error_limit failures, the method returns and allows the
    client to exit.
    """
    while True:
      if self.http_manager.ErrorLimitReached():
        return

      # Check if there is a message from the nanny to be sent.
      self.client_worker.SendNannyMessage()

      now = time.time()
      # Check with the foreman if we need to
      if (now > self.last_foreman_check +
          config.CONFIG["Client.foreman_check_frequency"]):
        # We must not queue messages from the comms thread with blocking=True
        # or we might deadlock. If the output queue is full, we can't accept
        # more work from the foreman anyways so it's ok to drop the message.
        try:
          self.client_worker.SendReply(
              rdf_protodict.DataBlob(),
              session_id=rdfvalue.FlowSessionID(flow_name="Foreman"),
              require_fastpoll=False,
              blocking=False)
          self.last_foreman_check = now
        except queue.Full:
          pass

      try:
        self.RunOnce()
      except Exception:  # pylint: disable=broad-except
        # Catch everything, yes, this is terrible but necessary
        logging.warning("Uncaught exception caught: %s", traceback.format_exc())
        if flags.FLAGS.pdb_post_mortem:
          pdb.post_mortem()

      # We suicide if our memory is exceeded, and there is no more work to do
      # right now. Our death should not result in loss of messages since we are
      # not holding any requests in our input queues.
      if (self.client_worker.MemoryExceeded() and
          not self.client_worker.IsActive() and
          self.client_worker.InQueueSize() == 0 and
          self.client_worker.OutQueueSize() == 0):
        logging.warning("Memory exceeded - exiting.")
        self.client_worker.SendClientAlert("Memory limit exceeded, exiting.")
        # Make sure this will return True so we don't get more work.
        # pylint: disable=g-bad-name
        self.client_worker.MemoryExceeded = lambda: True
        # pylint: enable=g-bad-name
        # Now send back the client message.
        self.RunOnce()
        # And done for now.
        sys.exit(-1)

      self.timer.Wait()