【问题标题】:Download can't finish when I use StreamingHttpResponse in Django当我在 Django 中使用 StreamingHttpResponse 时下载无法完成
【发布时间】:2021-10-09 04:56:48
【问题描述】:

我在谷歌云上使用 Django。自从我更新 docker 映像后,下载文件页面一直没有工作。下载文件页面程序如下。

def file_iterator(file, chunk_size=512):
    with open(file, 'rb') as f:
        while True:
            c = f.read(chunk_size)
            if c:
                yield c
            else:
                break

def download_view(request, format, pk):
    user = get_user(request)
    sentence = Sentence.objects.get(pk=pk)
    if not default_storage.exists(sentence.file.name):
        logger.warning(f'This file has been deleted pk: {pk} user: {user} file_name:{sentence.file.name}')
        raise Http404()
    
    file_name = f'{user.pk}{sentence.pk}.{format}'
    file_path = sentence.file.name
    if format == 'mp3':
        with open(file_path,'wb') as f:
            f.write(sentence.file.read())
    elif format == 'wav':
        file_path = AudioSplitter().mp3_to_wav(sentence)
    else:
        return HttpResponse('format error')
    
    response = StreamingHttpResponse(file_iterator(file_path))
    response['Content-Type'] = 'audio/mpeg' if format == 'mp3' else 'audio/wav'
    response['Content-Disposition'] = f'attachment;filename="{file_name}"'
    return response

谷歌云运行有下载文件限制。所以这个程序使用了StreamingHttpResponse。它返回分块的文件数据。当我从这个视图下载文件时,Download 堆积在 200 ~ 224KB 左右。

此问题发生在 2021 年 8 月 17 日。我当天构建了 3 个映像。

  1. 2021/08/17 10:24
  2. 2021/08/17 15:54
  3. 2021/08/17 20:58

第一个容器可以下载文件。但是,第二个和第三个容器无法从视图中下载文件。而且所有构建的容器在​​第一个容器之后都无法下载文件。

第一个和第二个容器有什么区别?

我在admin.py 中更改了一行,它只是添加了list_display_links = None

我检查了 python 模块版本和 python 版本。不过还是一样的。

当我运行docker images时,我发现图像大小不同。

REPOSITOR              TAG       IMAGE ID       CREATED          SIZE
gcr.io/***/***       8f6ae66   62d086d8f30c   7 weeks ago      2.07GB <-- 1st
gcr.io/***/***       bdf4a43   f67948780215   7 weeks ago      2.39GB <-- 2nd

第一个容器为 2.07GB,第二个容器为 2.39GB。我的 dockerfile 正在使用FROM python:3.9。 8 月 17 日 python3.9 图片有更新吗??

我用第一张图片构建了相同的代码。当然,此图像有下载页面问题,容器大小为 2.28GB。它比第一个图像大。 Python模块有一些差异,python版本已经更新到python 3.9.7。

我认为这个问题来自 python 的 docker image。我该如何解决这个问题?

更新

  1. 我把图片改成了python: 3.8。问题已重现。
  2. 我在下载堆叠时发现了这个错误。 uwsgi_response_write_body_do() TIMEOUT !!!

环境

第一张和第二张图片环境。

  • 版本:nginx/1.14.2
  • uWSGI==2.0.19.1

# nginx-app.conf

# the upstream component nginx needs to connect to
upstream django {
    server unix:/code/app.sock; # for a file socket
    # server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on, default_server indicates that this server block
    # is the block to use if no blocks match the server_name
    listen      8080;

    # the domain name it will serve for
    server_name xxx.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 10M;   # adjust to taste
    # set timeout
    uwsgi_read_timeout 900;
    proxy_read_timeout 900;
    # Django media
    location /media  {
        alias /code/app/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /code/app/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /code/uwsgi_params; # the uwsgi_params file you installed
    }
}



[uwsgi]
# this config will be loaded if nothing specific is specified
# load base config from below
ini = :base

# %d is the dir this configuration file is in
socket = %dapp.sock
master = true
processes = 4
max-requests = 1000                  ; Restart workers after this many requests
max-worker-lifetime = 3600           ; Restart workers after this many seconds
reload-on-rss = 512                  ; Restart workers after this much resident memory
worker-reload-mercy = 60             ; How long to wait before forcefully killing workers


【问题讨论】:

    标签: python docker google-cloud-run


    【解决方案1】:

    我解决了这个问题。我认为它是由这个错误引起的。

    uwsgi_response_write_body_do() TIMEOUT !!!

    我添加睡眠并更改块大小。

    # change chunk size from 512 byte to 1 MB, because it sleep 0.1 sec each loop.
    
    def file_iterator(file, chunk_size=1024 * 1024):
        with open(file, 'rb') as f:
            while True:
                time.sleep(0.1) # <-- add sleep
                c = f.read(chunk_size)
                if c:
                    yield c
                else:
                    break
    
    

    附:我试过this solution。但它对我没有影响。

    更新

    当我检查自己下载时。它工作正常。但是请求延迟非常慢。大约15~18分钟。当我运行第一张图片时,大约是 0.2 ~ 0.3 秒。并且 Charged Container 实例时间也增加了 5 倍。

    1 小时

    1 天

    我觉得这个解决方案是急救。我洞了一些答案真正的解决方案。

    2021/11/02 更新

    我找到了真正的解决方案! uWSGI 套接字连接有问题。我改变了端口连接。现在我的应用程序返回结果非常正常。

    This is my settings

    注意:这是正常的uWSGI PORT连接设置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-16
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 2016-07-24
      • 2023-03-13
      • 2013-12-31
      相关资源
      最近更新 更多