Ошибка получения в приложении Flask/IIS при больших загрузках

У меня есть приложение Flask, работающее на сервере Windows, использующее IIS в качестве обратного прокси-сервера для сервера приложений официантки. Он находится за локальным диспетчером трафика F5 моей организации. Ключевой функцией приложения является обработка больших (до 4 ГБ) загрузок файлов с последующей обработкой и задачами базы данных. После отправки формы процесс выглядит следующим образом:

  1. Начать загрузку частями.

  2. Соберите фрагменты на сервере в полный файл.

  3. Вызовите маршрут Flask для асинхронной обработки повторно собранного файла.

  4. Добавьте метаданные файла в базу данных.

Все работает так, как ожидалось, когда я использую сервер разработки Flask или Waitress напрямую без IIS. Однако описанный выше процесс завершается сбоем после шага 2 в рабочей функции sendMetadata (с IIS), но только для загрузок большего размера (2+ ГБ), что приводит к ошибке блока catch Failed to fetch и сетевой ошибке ERR_CONNECTION_RESET.

document.addEventListener("DOMContentLoaded", function () {
  const form = document.getElementById("caseForm");
  const fileInput = document.getElementById("uploaded_file");

  form.addEventListener("submit", async function (e) {
    const file = fileInput.files[0];

    await handleUpload(file);
  });

  async function handleUpload(file) {
    try {
      const uuidResponse = await fetch(
        "{{ url_for('/*get_uuid*/') }}",
        {
          method: "POST",
          headers: {
            "X-CSRFToken": csrfToken,
          },
        }
      ).then((response) => response.json());

      async function uploadChunk(/*args*/) {
        /*get form data...*/
        try {
          const response = await fetch("{{ url_for('/*upload_chunk*/') }}", {
            method: "POST",
            body: chunkFormData,
            headers: {
              "X-CSRFToken": csrfToken,
            },
          }).then((response) => response.json());

          if (response.success) {
            /*success logic*/
          } else {throw new Error(/*error message*/);}
        } catch (error) {
          /*retry logic*/
        }
      }
    } catch (error) {
        /*error handling*/
    }
      async function uploadFileInChunks() {
        const uploadPromises = [];
        for (let i = 0; i < totalChunks; i += concurrentUploads) {
          const chunkPromises = [];
          for (let j = 0; j < concurrentUploads && i + j < totalChunks; j++) {
            chunkPromises.push(uploadChunk(i + j));
          }
          await Promise.all(chunkPromises);
        }
      }

      await uploadFileInChunks();

      await sendMetadata(uniqueFilename, file);
    }
    
// problem //
  async function sendMetadata(uniqueFilename, file) {
    const formData = new FormData(form);
    formData.append("uniqueFilename", uniqueFilename);
    formData.append("fileName", file.name);

    try {
      pingServer(/*send_metadata_url*/); // Debugging
      const response = await fetch(
        "{{ url_for('/*send_metadata*/') }}",
        {
          method: "POST",
          body: formData,
          headers: {
            "X-CSRFToken": csrfToken,
          },
        }
      ).then((response) => response.json());
      console.info("Response: ", response); // response is never received
      if (response.success) {
        /*success logic*/
      } else {
        /*error handling*/
      }
    } catch (error) {
      /*error handling*/
    }
  }
})

Функция отладки pingServer, которая отправляет запрос на тот же URL-адрес, что и функция выборки, работает и возвращает ответ от сервера. Однако сама функция выборки никогда не генерирует ответ от сервера, и время соединения истекает.

Учитывая, что 1) код работает для всех размеров файлов только на сервере разработки Flask и сервере Waitress, и 2) он работает с IIS в качестве обратного прокси, но только для файлов меньшего размера (менее 2 ГБ), я думаю, что это это проблема конфигурации IIS. Я максимально увеличил размер файла и параметры конфигурации тайм-аута, которые смог найти в IIS, как рекомендовано здесь и в других местах. Я также подтвердил, что ошибка происходит за пределами локального диспетчера трафика F5, поэтому я не думаю, что причиной является F5.

Я не понимаю, почему работают файлы меньшего размера, и даже для больших файлов загрузка и повторная сборка фрагментов работают (я вижу неповрежденный файл на сервере), но последующая функция выборки, похоже, не срабатывает. Кто-нибудь сталкивался с чем-то подобным, прежде чем я попытаюсь найти обходной путь?

Новые приложения с использованием ChatGPT
Новые приложения с использованием ChatGPT
Я собираюсь вернуться к теме, которую уже освещал ранее, - чатгпт.
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Другой маршрут в Flask Python
Другой маршрут в Flask Python
Flask - это фреймворк, который поддерживает веб-приложения. В этой статье я покажу, как мы можем использовать @app .route в flask, чтобы иметь другую...
0
0
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете попытаться увеличить максимальный размер загружаемого файла, изменив maxAllowedContentLength в файле web.config.

<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength = "4294967295" />
    </requestFiltering>
  </security>
</system.webServer>

Спасибо. К сожалению, я уже превысил maxAllowedContentLength в своем web.config. Часть сценария для загрузки работает нормально... Я вижу файлы в соответствующем временном каталоге на сервере. По какой-то причине, похоже, вызов sendMetadata fetch не получает ответа от сервера.

Dan Shepherd 16.07.2024 16:48

Получаете ли вы какие-либо другие сообщения об ошибках? Например, в консоли или средстве просмотра событий.

samwu 17.07.2024 09:20

Консоль в конце концов выдает ошибку 500 (err_connection_reset), и блок catch сообщает «не удалось получить». Я не вижу ничего очевидного в средстве просмотра событий, но признаю, что не так хорошо с этим знаком.

Dan Shepherd 17.07.2024 16:38

Попробуйте использовать трассировку неудачных запросов, чтобы просмотреть подробную информацию об ошибке 500. Это создаст подробный файл журнала, который поможет вам выявить проблему.

samwu 18.07.2024 05:52

Вот фрагмент трассировки неудачного запроса: failureReason = "TIME_TAKEN" statusCode = "200" triggerStatusCode = "0" timeTaken = "270688". (Что бы это ни стоило, когда я загружаю тот же файл на сервер разработки, процесс не занимает почти столько времени, поэтому я не думаю, что это проблема простого превышения лимита времени ожидания) где-то.

Dan Shepherd 18.07.2024 16:43

Одних только этих сообщений недостаточно для анализа вашей проблемы. Выложите, пожалуйста, полный лог.

samwu 19.07.2024 12:07

Приносим извинения — файлы журналов огромны и сокращаются, и я не совсем уверен, как определить соответствующие данные. Я переконфигурировал код, чтобы сделать запрос POST заранее, прежде чем отправлять фрагменты файла на сервер. Эта стратегия работает – однако первоначальный запрос теперь достигает сервера через 2-3 минуты (но со временем это происходит). Я все еще подозреваю, что это проблема с моей конфигурацией IIS.

Dan Shepherd 23.07.2024 21:31
Ответ принят как подходящий

Обнаружена проблема... Я передал всю форму (включая загруженный файл) объекту FormData, а не извлекал только поля текстовой формы. Это привело к попытке отправить форму с огромным размером содержимого, который, насколько я понимаю, превышал максимальный размер полезной нагрузки IIS в 2 ГБ (помимо того, что это было избыточно, поскольку файл уже был загружен частями).

const formData = new FormData(form);
formData.append("uniqueFilename", uniqueFilename);

В конце концов проблема была решена путем создания пустого объекта FormData и добавления значений отдельных полей формы.

const formData = new FormData();
formData.append("uniqueFilename", uniqueFilename)

Другие вопросы по теме