Executando verificação de segurança...
3

Bacana, me identifiquei com o post pois recentemente tive esse mesmo problema com a diferença que o relatório que o sistema gera é em pdf ou planilha excel.
No meu caso utilizei streaming de dados com generator do python com fastapi e no front-end alterei o fluxo para abrir o download em uma aba separada, dessa forma o browser gerencia o download do arquivo e o fluxo fica livre para o usuário.

Carregando publicação patrocinada...
1

Aí sim, é uma otima solução também. Você consegue compartilhar alguma referencia que te ajudou na época?

Eu tentei essa abordagem também, mas não encontrei uma maneira do browser fazer o download via stream, eu ia ter que baixar como stream na memória e depois fazer o download na máquina do usuário, então preferi fazer via fila, salvar no bucket e depois notificar o usuário pra ele baixar o arquivo processado direto do bucket.

3

Sua solução é muito elegante, cumpre muito bem o papel.

Um pequeno exemplo de como eu fiz, adaptei para .csv:

Python / Fastapi

import csv
import io
import random
import string

def gerar_dados_csv(tamanho_desejado_mb):
    data = io.StringIO()
    writer = csv.writer(data)
    writer.writerow(["ID", "NAME", "AGE", "COUNTRY"])
    total_size = 0

    while total_size < tamanho_desejado_mb * 1024 * 1024:
        id = random.randint(1, 1000)
        name = ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))
        age = random.randint(20, 60)
        country = random.choice(['Brazil', 'India', 'USA', 'Canada', 'UK'])

        writer.writerow([id, name, age, country])

        chunk = data.getvalue()
        total_size += len(chunk)

        data.seek(0)
        data.truncate(0)

        yield chunk


@router.get('/csv/{tamanho}')
async def get_pdf(tamanho: int):

    nome_arquivo = f'relatorio.csv'
    headers = {"Content-Disposition": f"attachment; filename={nome_arquivo}", 'x-filename': nome_arquivo}

    return StreamingResponse(gerar_dados_csv(tamanho), media_type='application/csv', headers=headers)

Javascript

  /**
   *  Método para realizar download em uma nova aba, com responsabilidade
   *  do processo de download a cargo do browser.
   *
   * @param {String} url para download
   */
  async function fileDownload(url) {

    try {
      // url completa, com path variables e query params.
      const _url = `${axiosAPI.defaults.baseURL}${url}`
      const anchorElement = document.createElement('a')

      anchorElement.setAttribute("href", _url)
      anchorElement.setAttribute("target", "_blank")

      document.body.appendChild(anchorElement)
      anchorElement.click()

      document.body.removeChild(anchorElement)
    }
    catch (error) {
      console.log('error: ', error)
      throw new Error("Erro ao baixar arquivo.")
    } 
  }