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
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