Я использую приложение Django в Heroku, которое обрабатывает несколько загрузок изображений от пользователя и сохраняет их в Amazon S3. Проблема заключается в том, что для выполнения этого процесса обычно требуется более 30 секунд (ограничение по времени выполнения Heroku).
Я проверил это, и строка, которая занимает больше времени, является той, которая сохраняет файл изображения в ImageField. Это делается так, потому что изображение должно быть обрезано и обработано ProcessImageFile (). Однако эта функция не занимает много времени, но сам метод сохранения, возможно, потому что он сохраняет файлы в S3 один за другим, сохраняя их.
Вот представление (пропущены нерелевантные строки):
@login_required
def image_create(request):
if request.method == 'POST':
images = request.FILES.getlist("files")
crop_points = json.loads( request.POST.get('crop_points'))
#Validation of inputs in the form: images and other fields
if len(images) < 3 : return JsonResponse({'val_result': 'min_error'})
if len(images) > 12: return JsonResponse({'val_result': 'max_error'})
#We Create the gallery, iterate over the images provided by the form, validate, insert custom fields and save them in bulk associating it to the gallery.
with transaction.atomic():
new_items = []
gallery = Gallery.objects.create( user=request.user )
for i, img_file in enumerate(images):
new_item = Image()
new_item.user = request.user
#-----THIS IS THE PART WHICH TAKES MOST OF THE VIEW PROCESSING TIME: IT IS NOT THE ProcessImageFile FUNCTION, BUT THE SAVE METHOD ITSELF
new_item.image.save( 'img'+ str(i) + '.jpg', content = ProcessImageFile(img_file, crop_points), save=False )
#---------------------------------------------------------------------------------------------------------------------------------------
new_items.append( new_item )
created_objects = Image.objects.bulk_create( new_items )
Belonging.objects.bulk_create( [ Belonging(gallery=gallery, content_id = item.id) for item in new_items] )
for img in created_objects:
img.create_tags(gallery = gallery) #<-We save the notifications for bulk create
return JsonResponse({'status': 'ok', 'gallery': gallery.id})
else:
form = MultiUploadImageForm()
return render(
request,
'upload/create.html',
{'form': form}
)
#I THOUGHT THIS COULD BE THE FUNCTION TAKING TIME BUT IT IS NOT:
def ProcessImageFile(img_file, crop_points):
img = ImageProcessor.open(img_file)
cropped_img = img.crop( ( int(crop_points[0]), int(crop_points[1]), int(crop_points[2]), int(crop_points[3])))
img_io = BytesIO()
cropped_img.save( img_io, format='JPEG', quality=100)
return ContentFile( img_io.getvalue())
Я уже пытался использовать Celery для обработки загрузки файла в отдельной задаче, но проблема здесь заключается в передаче запроса илифайлы изображений для задачи, так как они должны быть сериализованы. В любом случае, я полагаю, что здесь есть что-то неэффективное, и что этот простой вид не должен занимать более 30 секунд для загрузки пяти изображений в S3 и возврата ответа. Возможно, решением будет отправить все изображения вместе на S3 или сохранить их другим способом, я не знаю.