Django + Gunicorn + Nginx + Python -> Ссылка для загрузки файла с веб-сервера

На моей веб-странице, обслуживаемой веб-сервером Debian, размещенным на amazon-lightsail за nginx и gunicorn, пользователь может послать запрос на запуск функции представления Django. Эта функция добавляет некоторую работу в фоновый процесс и каждые 5 с проверяет, создал ли фоновый процесс файл. Если файл существует, представление посылает ответ, и пользователь может скачать файл. Иногда этот процесс может занять много времени, и пользователь получает сообщение 502 bad gateway. Если процесс занимает слишком много времени, я хочу отправить пользователю электронное письмо со ссылкой, по которой он может скачать файл с веб-сервера. Я знаю, как отправить письмо после завершения процесса, но не знаю, как передать файл пользователю по ссылке для скачивания.

Это конец моей функции просмотра :

    print('######### Serve Downloadable File #########')
    while not os.path.exists(f'/srv/data/ship_notice/{user_token}'):
        print('wait on file is servable')
        time.sleep(5)
    
    # Open the file for reading content
    path = open(filepath, 'r')
    # Set the mime type
    mime_type, _ = mimetypes.guess_type(filepath)
    # Set the return value of the HttpResponse
    response = HttpResponse(path, content_type=mime_type)
    # Set the HTTP header for sending to browser
    response['Content-Disposition'] = f"attachment; filename={filename}" 
    # Return the response value
    return response

Другая модель функции, которая отправляет почту пользователю после завершения процесса:

def send_mail_precipitation(filepath, user_token, email):
    from django.core.mail import EmailMessage
    import time
    import os
    
    while not os.path.exists(f'/srv/data/ship_notice/{user_token}'):
        print('wait 30secs')
        time.sleep(30)
            
    msg = EmailMessage(
        subject = 'EnviAi data',
        body = 'The process is finished, you can download the file here.... ',
        to = [email]
    )
    msg.send()

Файл слишком большой, чтобы отправить его с помощью msg.attach_file(filepath)

Какие у меня есть варианты, чтобы послать пользователю ссылку для загрузки этих файлов. Нужно ли мне устанавливать ftp-сервер/папку, или какие у меня есть варианты? И какую работу мне нужно проделать, если я хочу, чтобы ссылка была действительна только 72 часа? Большое спасибо!

Не прямой ответ, но возможный путь.

Такие длительно выполняющиеся задачи обычно реализуются с помощью дополнительного инструмента, такого как Celery. Плохая практика - позволять конечной точке view/api работать столько, сколько потребуется, и заставлять запрашивающий процесс ждать завершения. Хорошей практикой является предоставление ответа так быстро, как вы можете.

В вашем случае это будет:

  • создайте задачу celery для сборки вашего файла (создание задачи происходит быстро)
  • возвращает идентификатор задачи в ответ
  • запросите статус задачи из фронтенда с заданным идентификатором задачи
  • после выполнения задания должен быть возвращен URL файла

Также можно добавить код on_success, который будет выполнен (запущен Celery автоматически), когда задача будет выполнена. Вы можете вызвать свою email_user_when_file_is_ready функцию в реакции на это событие.

Чтобы сделать файлы доступными для загрузки, вы можете добавить местоположение в конфигурацию nginx, как вы это делали для статических и медиа папок. Поместите ваши файлы в папку с привязкой к местоположению и все. Дайте пользователю URL вашего файла.

Вернуться на верх