From 7b292a2c170ac7df904b1f4c25d539dbcc1cf1f3 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 7 Apr 2020 18:37:34 +0200 Subject: [PATCH] api_views: use loop to prevent NFS errors on GET (#41379) File can disapear more frequently on NFS as open() is not atomic (NFS filehandle refers to an inode but they don't lock it like an open file descriptor). --- petale/api_views.py | 49 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/petale/api_views.py b/petale/api_views.py index 6dc1edb..b1b4240 100644 --- a/petale/api_views.py +++ b/petale/api_views.py @@ -21,8 +21,11 @@ try: from functools import reduce except ImportError: pass - import requests +try: + from time import process_time +except ImportError: + from time import clock as process_time from django.utils.six.moves.urllib import parse as urlparse @@ -180,30 +183,32 @@ class PetalAPIView(APIView): @logit def get(self, request, partner_name, cut_uuid, petal_name): - logger = logging.getLogger(__name__) if_none_match = request.META.get('HTTP_IF_NONE_MATCH') if_none_match = if_none_match and [x.strip() for x in if_none_match.split(',')] - petal = self.get_petal(partner_name, cut_uuid, petal_name) - if if_none_match: - if if_none_match == ['*'] or petal.etag in if_none_match: - return Response( - status=status.HTTP_304_NOT_MODIFIED, - headers={ - 'ETag': petal.etag - } - ) - # verify file exists before creating a StreamingHttpResponse - # as StreamingHttpResponse generate its content after the Django global try/catch - try: - petal.data.open() - except IOError as e: - logger.error('file not found "%s": %s', petal.data.path, e) - return HttpResponse('missing file', status=500) - response = StreamingHttpResponse( - petal.data.chunks(), - content_type=petal.content_type, - ) + start = process_time() + while process_time() - start < 10: + petal = self.get_petal(partner_name, cut_uuid, petal_name) + if if_none_match: + if if_none_match == ['*'] or petal.etag in if_none_match: + return Response( + status=status.HTTP_304_NOT_MODIFIED, + headers={ + 'ETag': petal.etag + } + ) + # verify file exists before creating a StreamingHttpResponse + # as StreamingHttpResponse generate its content after the Django global try/catch + try: + petal.data.open(mode='rb') + response = HttpResponse(petal.data.read(), content_type=petal.content_type) + except IOError: + continue + finally: + petal.data.close() + break + else: + return HttpResponse(status=500, reason='Too many updates') response['ETag'] = petal.etag return response