Как использовать Django File Storage для обмена файлами между API и рабочим - PullRequest
1 голос
/ 24 октября 2019

Цель

Я хочу создать локальное приложение для создания составных докеров таким образом, чтобы у меня было 5 служб.

  • Redis
  • Postgres
  • RabbitMQ
  • Django API
  • Django Worker

В этом развертывании пользователь загружает файл через конечную точку API. Эта конечная точка сохранит файл в поле FileField в модели.

В отдельной транзакции пользователь будет запускать асинхронную задачу через отдельную конечную точку. Это задание будет отвечать за

  • загрузку файла
  • извлечение файла
  • пинать подзадачи для выполнения intermediate processing steps
  • загрузить файлрезультаты обработки в базу данных

intermediate processing steps НЕ ДОЛЖЕН загружать какие-либо файлы в базу данных.

intermediate processing steps должен использовать внутреннее хранилище файлов djangoРешение для загрузки и загрузки файлов там. Это реализовано с помощью иерархии файловой системы, которая не относится к этому вопросу.

Проблема

Мне удалось заставить мою локальную файловую систему работать с этой конфигурацией. Если я запускаю бэкэнд из redis, postgres и rabbitmq. А затем я запускаю API и Worker на своей машине локально, все работает нормально.

Когда я создаю конфигурацию docker-compose и отсоединяю все. Операция, кажется, сломана. И в моем журнале docker-compose, что я вижу:

worker_1  | [2019-10-23 22:27:34,626: WARNING/ForkPoolWorker-2] //--------------------------------------------------------------------------------
worker_1  | [2019-10-23 22:27:34,627: WARNING/ForkPoolWorker-2] // BEGINNING TASK
worker_1  | [2019-10-23 22:27:34,627: WARNING/ForkPoolWorker-2] //--------------------------------------------------------------------------------
worker_1  | [2019-10-23 22:27:34,628: WARNING/ForkPoolWorker-2] // Root Job - 183916ca-f6e6-4e7c-a997-e8f516ccf8be
worker_1  | [2019-10-23 22:27:34,628: WARNING/ForkPoolWorker-2] // Parent Job - None
worker_1  | [2019-10-23 22:27:34,628: WARNING/ForkPoolWorker-2] // Current Job - 183916ca-f6e6-4e7c-a997-e8f516ccf8be
worker_1  | [2019-10-23 22:27:34,628: WARNING/ForkPoolWorker-2] //--------------------------------------------------------------------------------
worker_1  | [2019-10-23 22:27:34,629: WARNING/ForkPoolWorker-2] // PERFORMING DATA SET PRE PROCESSING
worker_1  | [2019-10-23 22:27:34,629: WARNING/ForkPoolWorker-2] //--------------------------------------------------------------------------------
worker_1  | [2019-10-23 22:27:34,629: WARNING/ForkPoolWorker-2] {'data_set_id': 1, 'starting_node': 'Live', 'organization_id': 1}
worker_1  | [2019-10-23 22:27:34,630: WARNING/ForkPoolWorker-2] Downloading the files required to run!
worker_1  | [2019-10-23 22:27:34,645: WARNING/ForkPoolWorker-2] Downloading remote file `organizations/1/data_sets/flow_cytometry/triple_hello_world_payload.tgz`
worker_1  | [2019-10-23 22:27:34,646: WARNING/ForkPoolWorker-2] Exists: `False`
worker_1  | [2019-10-23 22:27:34,646: WARNING/ForkPoolWorker-2] ERROR occured: [Errno 2] No such file or directory: '/opt/api_webserver/media/organizations/1/data_sets/flow_cytometry/triple_hello_world_payload.tgz'.
worker_1  | [2019-10-23 22:27:34,653: INFO/ForkPoolWorker-2] Task api.versions.v1.tasks.main_task.main_task[183916ca-f6e6-4e7c-a997-e8f516ccf8be] succeeded in 0.02647909999359399s: {'iteration': 0, 'completion': 0, 'status': 'ERROR', 'message': 'Excecuting `main_task` failed!', 'error': 'Error in `main_task`: [Errno 2] No such file or directory: \'/opt/api_webserver/media/organizations/1/data_sets/flow_cytometry/triple_hello_world_payload.tgz\'.'}

Если я захожу в worker docker container и проверяю файловую систему, путь НЕ существует для каталога media ифайл.
Если я захожу в api docker container и проверяю файловую систему, существует ли путь для каталога и файла media.

Соответствующий код

Я выигралне предоставляет код представления или API-код, поскольку API работает нормально.

Загрузка и извлечение файла обрабатываются в процессе workers с использованием интерфейса django default_storage.

API интерфейса хранилища по умолчанию в Django

Эта проблема связана с работником, поэтому вот некоторые из связанных кодов.

worker.py

# Python Standard Libraries
import os
# Third-Party Libraries
import tempfile
# Custom
from models.data_set_model import DataSet
from tasks.helpers import download_remote_file


def download_data_set(data_set_id):
    print("Downloading the files required to run!")
    data_set = DataSet.objects.get(id=data_set_id)

    remote_file_path = data_set.file.name
    remote_file_name = os.path.basename(remote_file_path)

    temporary_directory_path = tempfile.mkdtemp()
    temporary_compressed_file_path = os.path.join(temporary_directory_path, remote_file_name)

    download_remote_file(remote_file_path, temporary_compressed_file_path)

    return temporary_compressed_file_path

helpers.py

# Python Standard Libraries
# N/A
# Third-Party Libraries
from django.core.files.storage import default_storage
# CustomLibraries
# N/A


def download_remote_file(remote_file_path, local_file_path):
    print(f"Downloading remote file `{remote_file_path}`")
    print(f"Exists: `{default_storage.exists(remote_file_path)}`")
    remote_file_contents = None
    with default_storage.open(remote_file_path) as remote_file_handle:
        print("Reading file contents")
        remote_file_contents = remote_file_handle.read()

    print(f"Placing remote file contents into `{local_file_path}`")
    with open(local_file_path, "wb") as local_file_handle:
        local_file_handle.write(remote_file_contents)

нерешенные вопросы

  • Что я делаю не так?
  • Какой идиоматический способ загрузки файлов наработник из системы FileStorage API?
  • Разве команда default_storage.open() не должна указывать на файловую систему API и иметь возможность загружать файлы? t
    • Если нет, то какие конфигурации я могу настроить на рабочем месте для поддержки этого?
  • Работает ли это только локально, потому что файловая система является общей, ипричина в том, что docker-compose разбивает их на отдельные среды?

1 Ответ

2 голосов
/ 12 ноября 2019

Если вы в docker compose, просто создайте общий том докера между вашим API и работником и смонтируйте его в хорошо известной точке в обоих контейнерах, например /mnt/share. Обязательно сохраните файлы там в API, и тогда работник сможет получить к ним доступ, используя ту же модель, поскольку настройки (например, MEDIA_ROOT) будут указывать как API, так и Worker на /mnt/share.

...