Храните статические файлы на S3, но staticfiles.json манифест локально - PullRequest
0 голосов
/ 17 мая 2018

У меня есть приложение Django, работающее на Heroku.Для хранения и обслуживания моих статических файлов я использую django-storerages с моей корзиной S3, а также стандартную Django ManifestFilesMixin.Я также использую django-pipe .

В коде:

from django.contrib.staticfiles.storage import ManifestFilesMixin
from storages.backends.s3boto import S3BotoStorage
from pipeline.storage import PipelineMixin

class S3PipelineManifestStorage(PipelineMixin, ManifestFilesMixin, S3BotoStorage):
    pass

Настройка работает, однако манифест staticfiles.json равен также хранится на S3.Я вижу две проблемы с этим:

  1. Экземпляр хранилища моего приложения должен будет извлечь staticfiles.json из S3, а не просто получить его из локальной файловой системы.Это не имеет большого смысла с точки зрения производительности.Единственным потребителем файла манифеста является само серверное приложение, поэтому оно может также храниться в локальной файловой системе, а не удаленно.

    Я не уверен, насколько серьезна эта проблема, поскольку я полагаю (илинадеюсь), что серверное приложение кэширует файл после его прочтения один раз.

  2. Файл манифеста записывается при развертывании с помощью collectstatic, поэтому, если какой-либо уже запущенэкземпляры предыдущей версии серверного приложения считывают файл манифеста с S3 до того, как развертывание завершится, и новый slug вступит во владение, они могут получить неправильные статические файлы - те, которые должны обслуживаться только для экземпляров нового slug.

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

    Этот сценарий, как описано, специфичен для Heroku, но я думаю, что будут похожие проблемыс другими средами.

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

Возможно ли это?

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Ответ @John и Kogan великолепен, но не дает полного кода, необходимого для этой работы: как упоминал @Danra, вам также необходимо сохранить staticfiles.json в исходной папке, чтобы сделать эту работу. Вот код, который я создал на основе приведенного выше ответа:

import json
import os
from django.conf import settings
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage

from whitenoise.storage import CompressedManifestStaticFilesStorage
# or if you don't use WhiteNoiseMiddlware:
# from django.contrib.staticfiles.storage import ManifestStaticFilesStorage


class LocalManifestStaticFilesStorage(CompressedManifestStaticFilesStorage):
    """
    Saves and looks up staticfiles.json in Project directory
    """
    manifest_location = os.path.abspath(settings.BASE_DIR)  # or settings.PROJECT_ROOT depending on how you've set it up in your settings file.
    manifest_storage = FileSystemStorage(location=manifest_location)

    def read_manifest(self):

        try:
            with self.manifest_storage.open(self.manifest_name) as manifest:
                return manifest.read().decode('utf-8')
        except IOError:
            return None

    def save_manifest(self):
        payload = {'paths': self.hashed_files, 'version': self.manifest_version}
        if self.manifest_storage.exists(self.manifest_name):
            self.manifest_storage.delete(self.manifest_name)
        contents = json.dumps(payload).encode('utf-8')
        self.manifest_storage._save(self.manifest_name, ContentFile(contents))

Теперь вы можете использовать LocalManifestStaticFilesStorage для вашего STATICFILES_STORAGE. При запуске manage.py collectstatic ваш манифест будет сохранен в вашей корневой папке проекта, и Django будет искать его там при обслуживании контента.

Если у вас есть развертывание с несколькими виртуальными машинами, обязательно запустите collectstatic только один раз и скопируйте файл staticfiles.json на все машины в вашем развертывании как часть вашего развертывания кода. Хорошая вещь в этом заключается в том, что даже если на некоторых машинах еще не установлено последнее обновление, они все равно будут обслуживать правильный контент (соответствующий текущей версии кода), так что вы можете выполнить постепенное развертывание там, где есть смешанное состояние.

0 голосов
/ 23 мая 2018

Некоторое время назад я прочитал эту статью , которая, как мне кажется, хорошо подходит для вашего случая.
Там в последнем абзаце существует следующее:

Где находится staticfiles.json?

По умолчанию staticfiles.json будет находиться в STATIC_ROOT, который является каталог, в котором собраны все статические файлы.
Мы размещаем все наши статические ресурсы в сегменте S3, что означает, что staticfiles.json по умолчанию будет синхронизироваться с S3. Однако мы хотели, чтобы он находился в каталоге кода, чтобы мы могли упаковать его и отправить на каждый сервер приложений.

В результате этого ManifestStaticFilesStorage будет искать staticfiles.json в STATIC_ROOT, чтобы прочитать сопоставления. Мы имеем переписать это поведение, поэтому мы подклассы ManifestStaticFilesStorage:

from django.contrib.staticfiles.storage import
ManifestStaticFilesStorage from django.conf import settings

class KoganManifestStaticFilesStorage(ManifestStaticFilesStorage):

    def read_manifest(self):
        """
        Looks up staticfiles.json in Project directory
        """
        manifest_location = os.path.abspath(
            os.path.join(settings.PROJECT_ROOT, self.manifest_name)
        )
        try:
            with open(manifest_location) as manifest:
                return manifest.read().decode('utf-8')
        except IOError:
            return None

С указанным выше изменением тег статического шаблона Django теперь будет читать сопоставления из staticfiles.json, находящиеся в корневом каталоге проекта.

Сам не использовал, поэтому дайте мне знать, если это поможет!

...