Fix leaking sockets after v2 list operation
This fixes the same problem with leaking file descriptors after the port to requests I16a7b02f2b10e506e91719712cf34ef0aea1afc0 does, but for the v2 api client. The paginate function in the list method has been refactored from a recursive generator to a non-recursive generator, which avoids issues with garbage collection holding the socket open. Change-Id: Iaa7a421e8c1acafb7b23bb3f55e50b9d2a9d030a Closes-Bug: #1428797
This commit is contained in:
@@ -54,40 +54,40 @@ class Controller(object):
|
|||||||
page_size = kwargs.get('page_size') or DEFAULT_PAGE_SIZE
|
page_size = kwargs.get('page_size') or DEFAULT_PAGE_SIZE
|
||||||
|
|
||||||
def paginate(url, page_size, limit=None):
|
def paginate(url, page_size, limit=None):
|
||||||
|
next_url = url
|
||||||
|
|
||||||
if limit and page_size > limit:
|
while True:
|
||||||
# NOTE(flaper87): Avoid requesting 2000 images when limit is 1
|
if limit and page_size > limit:
|
||||||
url = url.replace("limit=%s" % page_size,
|
# NOTE(flaper87): Avoid requesting 2000 images when limit
|
||||||
"limit=%s" % limit)
|
# is 1
|
||||||
|
next_url = next_url.replace("limit=%s" % page_size,
|
||||||
|
"limit=%s" % limit)
|
||||||
|
|
||||||
resp, body = self.http_client.get(url)
|
resp, body = self.http_client.get(next_url)
|
||||||
for image in body['images']:
|
for image in body['images']:
|
||||||
# NOTE(bcwaldon): remove 'self' for now until we have
|
# NOTE(bcwaldon): remove 'self' for now until we have
|
||||||
# an elegant way to pass it into the model constructor
|
# an elegant way to pass it into the model constructor
|
||||||
# without conflict.
|
# without conflict.
|
||||||
image.pop('self', None)
|
image.pop('self', None)
|
||||||
yield self.model(**image)
|
yield self.model(**image)
|
||||||
# NOTE(zhiyan): In order to resolve the performance issue
|
# NOTE(zhiyan): In order to resolve the performance issue
|
||||||
# of JSON schema validation for image listing case, we
|
# of JSON schema validation for image listing case, we
|
||||||
# don't validate each image entry but do it only on first
|
# don't validate each image entry but do it only on first
|
||||||
# image entry for each page.
|
# image entry for each page.
|
||||||
self.model.validate = empty_fun
|
self.model.validate = empty_fun
|
||||||
|
|
||||||
if limit:
|
if limit:
|
||||||
limit -= 1
|
limit -= 1
|
||||||
if limit <= 0:
|
if limit <= 0:
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
# NOTE(zhiyan); Reset validation function.
|
# NOTE(zhiyan); Reset validation function.
|
||||||
self.model.validate = ori_validate_fun
|
self.model.validate = ori_validate_fun
|
||||||
|
|
||||||
try:
|
try:
|
||||||
next_url = body['next']
|
next_url = body['next']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
for image in paginate(next_url, page_size, limit):
|
|
||||||
yield image
|
|
||||||
|
|
||||||
filters = kwargs.get('filters', {})
|
filters = kwargs.get('filters', {})
|
||||||
# NOTE(flaper87): We paginate in the client, hence we use
|
# NOTE(flaper87): We paginate in the client, hence we use
|
||||||
|
Reference in New Issue
Block a user