def FetchCompletedResponses(self, session_id, timestamp=None, limit=10000):
    """Fetch only completed requests and responses up to a limit."""
    if timestamp is None:
      timestamp = (0, self.frozen_timestamp or rdfvalue.RDFDatetime.Now())

    completed_requests = collections.deque(
        self.FetchCompletedRequests(session_id, timestamp=timestamp))

    total_size = 0
    while completed_requests:

      # Size reported in the status messages may be different from actual
      # number of responses read from the database. Example: hunt responses
      # may get deleted from the database and then worker may die before
      # deleting the request. Then status.response_id will be >0, but no
      # responses will be read from the DB.
      projected_total_size = total_size
      request_list = []
      while completed_requests:
        request, status = completed_requests.popleft()

        # Make sure at least one response is fetched.
        request_list.append(request)

        # Quit if there are too many responses.
        projected_total_size += status.response_id
        if projected_total_size > limit:
          break

      for request, responses in self.data_store.ReadResponses(request_list):

        yield (request, responses)
        total_size += len(responses)
        if total_size > limit:
          raise MoreDataException()
Fetch only completed requests and responses up to a limit.