Django api流csv文件并在线程中上传到s3

我有一个Django APIView,它生成CSV文件流并使用StreamingHttpResponse返回它。我也希望在单独的线程中将生成的文件也上传到s3,因为我不希望响应停止直到上传完成。

我想到将流保存在TemporaryFile对象中,并在流完成后使用它在单独的线程中触发s3上传。使用这种方法时,由于上下文管理器退出时文件自动关闭,因此无法使用上下文管理器。上传完成后,我不得不求助于手动关闭文件。我想避免此手动文件关闭过程。我该如何解决?

这是视图:

class CsvExportView(APIView):
    def get(self, request):
        response = StreamingHttpResponse(
                    streaming_content=get_file_stream(),
                    content_type='text/csv'
                )
        response['Content-Disposition'] = 'attachment; filename="{}"'.format('some_name')
        return response

Here is the get_file_stream() method:

import threading

from tempfile import TemporaryFile

class TempFileManager(object):
    def __init__(self):
        self._file = TemporaryFile()

    def get_file(self, parameter_list):
        pass

    def write_to_file(self, data)
        self._file.write(data)

    def close_file(self):
        self._file.close()

def get_file_stream():
    file_mng = TempFileManager()

    # get_csv_stream method is a generator that yields csv file content
    # by calling external api and complex data processing
    for data in get_csv_stream():

        # keep writing to temp file
        file_mng.write_to_file(data)

        # yield chunks to browser
        yield data

    # once all data is received
    # spawn a thread and do the upload
    # complete request lifecycle
    t = threading.Thread(target=upload_file_to_s3, args=(file_mng, ))
    t.start()

def upload_file_to_s3(self, manager):
    # some code to upload file
    upload(manager.get_file())

    # remember to close file
    manager.close_file()

上面的方法很好用,但是看起来很混乱并且容易出错。如果像这样使用上下文管理器,这会容易得多:

def get_file_stream():
    with TemporaryFile() as tmp:

        for data in get_csv_stream():
            # keep writing to temp file
            tmp.write(data)
            yield data

        upload_file_to_s3(tmp)

但是我不希望用户等到文件上传到s3之前,所以由于涉及线程,上下文管理器甚至在上传过程开始之前就可能关闭文件。

有谁知道更好的方法来处理这种情况?

评论