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).
This commit is contained in:
Benjamin Dauvergne 2020-04-07 18:37:34 +02:00
parent 9a2c6b23ed
commit 7b292a2c17
1 changed files with 27 additions and 22 deletions

View File

@ -21,8 +21,11 @@ try:
from functools import reduce from functools import reduce
except ImportError: except ImportError:
pass pass
import requests 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 from django.utils.six.moves.urllib import parse as urlparse
@ -180,30 +183,32 @@ class PetalAPIView(APIView):
@logit @logit
def get(self, request, partner_name, cut_uuid, petal_name): 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 = request.META.get('HTTP_IF_NONE_MATCH')
if_none_match = if_none_match and [x.strip() for x in if_none_match.split(',')] 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) start = process_time()
if if_none_match: while process_time() - start < 10:
if if_none_match == ['*'] or petal.etag in if_none_match: petal = self.get_petal(partner_name, cut_uuid, petal_name)
return Response( if if_none_match:
status=status.HTTP_304_NOT_MODIFIED, if if_none_match == ['*'] or petal.etag in if_none_match:
headers={ return Response(
'ETag': petal.etag 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: # verify file exists before creating a StreamingHttpResponse
petal.data.open() # as StreamingHttpResponse generate its content after the Django global try/catch
except IOError as e: try:
logger.error('file not found "%s": %s', petal.data.path, e) petal.data.open(mode='rb')
return HttpResponse('missing file', status=500) response = HttpResponse(petal.data.read(), content_type=petal.content_type)
response = StreamingHttpResponse( except IOError:
petal.data.chunks(), continue
content_type=petal.content_type, finally:
) petal.data.close()
break
else:
return HttpResponse(status=500, reason='Too many updates')
response['ETag'] = petal.etag response['ETag'] = petal.etag
return response return response