Загрузки не удаляются и не очищаются

Здравствуйте,

Недавно я стал последним оставшимся администратором и сопровождающим базового экземпляра образа Discourse Docker, который был изначально установлен на нашем сервере в 2021 году (по-моему) и в основном обновлялся кем-то другим. Уже какое-то время, возможно, с самого начала, у нас возникает проблема: файлы из мягко удалённых постов не становятся сиротами и не удаляются. Я пытаюсь устранить эту проблему уже несколько дней, так как устаревшие файлы продолжают накапливаться и занимать место на диске. Мы не используем S3, и места для загружаемых файлов, которые мы действительно хотим сохранить, у нас достаточно.

Я перенёс полный файл резервной копии Discourse, включая загрузки, на отдельный тестовый сервер, восстановив его с помощью нашего файла app.yml в соответствии с официальными руководствами по установке Discourse Docker, а затем восстановил резервную копию из командной строки. Обе установки работают идентично корректно, без других очевидных проблем, но проблема с загрузками сохраняется.

Мне не удаётся найти какие-либо соответствующие ошибки в логах, а Sidekiq выполняет задачи очистки по расписанию. Я запускал rake db:migrate на тестовой версии и многократно пересоздавал контейнер, пробовал окончательно удалять посты и проверять настройки. После окончательного удаления некоторых постов прямо из консоли Rails и попытки вручную запустить задачу очистки я заметил, что каталог tombstone немного увеличился в размере, и в нём изначально уже были какие-то файлы, значит, механизм работал в каких-то ситуациях, верно? Судя по небольшому увеличению размера, почти все устаревшие файлы до сих пор не обнаруживаются как сироты.

Ниже перечислены текущие соответствующие настройки панели администратора. Могу ли я установить последние два параметра в 0, чтобы фактически пропустить периоды отсрочки во время тестирования?

clean up uploads = true
clean orphan uploads grace period hours = 1
purge deleted uploads grace period days = 1

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

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

Пожалуйста, задавайте мне дополнительные вопросы, если это необходимо; я делаю всё возможное, чтобы решить эту проблему раз и навсегда.

Привет и добро пожаловать @Uphill4721 :slight_smile:

Кажется, в этих темах есть relevantная информация, если я не ошибаюсь:

Спасибо за быстрый ответ!

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

Вчера на тестовом сервере я выполнил эти команды, адаптированные для тем и сообщений, удалённых более 9 дней назад:

После этого я заметил незначительное увеличение размера содержимого директории tombstone и продолжаю следить за ситуацией из-за периода отложенного удаления. Всё ещё задаюсь вопросом, можно ли обойти время ожидания при тестировании, установив соответствующие настройки в ноль часов/дней.

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

На данном этапе я был бы лично более чем рад найти какое-либо рабочее ручное решение для постоянного удаления даже одной темы вместе с её сообщениями и загруженными файлами, на которые нет ссылок в другом месте. Однако это может стать серьёзной проблемой для других пользователей Discourse, которые естественно полагают, что настройки очистки в панели администратора работают так, как описано, но не обязательно замечают, если это не так, и в итоге оказываются с потенциально конфиденциальными загруженными файлами, которые должны были быть навсегда удалены, но фактически остаются в файловой системе. Наша проблема, к счастью, касается только потраченного впустую места на диске, но для кого-то другого это может быть гораздо хуже.

Есть ещё одно похожее упоминание всего два месяца назад:

How to Delete Uploaded Files? - #29 by anon98107012

Так что, есть ли какие-либо советы, как понять, является ли это ошибкой конфигурации с нашей стороны или настоящей ошибкой? В остальном мы очень довольны Discourse, и я крайне мотивирован решить эту проблему и помочь другим на этом пути.

Это чисто спекулятивно, но, взглянув на модели post, post_upload и upload, вы, вероятно, сможете обнаружить «сиротские» загрузки (объекты базы данных) с помощью следующего запроса:

Upload.find_by_sql("select * from uploads where id in (select upload_id from post_uploads where post_id not in (select id from posts))")

Я не тестировал этот код, поэтому не могу гарантировать, что он корректно найдёт сиротские загрузки или даже выполнится без ошибок. На случай, если он не сработает «как есть», и кто-то другой сможет его исправить, а также просто для всех заинтересованных, я распишу его логику.

  1. Upload.find_by_sql() возвращает коллекцию объектов Upload, которые соответствуют указанному SQL-запросу.
  2. (select id from posts) получает все идентификаторы существующих постов.
  3. (select upload_id from post_uploads where post_id not in () получает все идентификаторы загрузок, привязанных к постам, для которых пост не существует.
  4. select * from uploads where id in () получает все загрузки, соответствующие этим идентификаторам загрузок постов.

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

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

Плагины также могут создавать и хранить загрузки. Я не знаю, что происходит с ними, если, скажем, плагин удаляется. Мне кажется, что данные плагинов остаются в базе данных после удаления плагина, что потенциально означает, что любые загрузки, созданные этим плагином, в такой ситуации никогда не удаляются.

Спасибо за ответ!

Запрос работает, но показывает только две загрузки и их детали. Должно быть сотни или тысячи загрузок, соответствующих критериям «осиротевших» файлов; большинство из них — изображения, изначально загруженные пользователями при создании обычных постов.

В настоящее время мы используем только официальные плагины:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-chat-integration.git
          - git clone https://github.com/discourse/discourse-prometheus.git
          - git clone https://github.com/discourse/discourse-bbcode-color
          - git clone https://github.com/discourse/discourse-data-explorer

Некоторое время после нашей первоначальной установки в процессе загрузки файлов произошёл своего рода пересмотр. Интересно, может ли это как-то быть связано с нашей ситуацией: A new era for file uploads in Discourse

Период льготного использования на тестовом сервере уже должен был истечь, но я не вижу никаких изменений в размере директории загрузок, и тестовые файлы всё ещё доступны. Что мне стоит проверить дальше? Может ли это быть вызвано какими-либо некорректными правами доступа к файловой системе или подобными проблемами? Есть ли простой способ это проверить? У меня заканчиваются идеи по конкретным направлениям поиска; всё остальное работает отлично, и это единственная проблема, с которой мы сталкиваемся на данный момент.

Пройдусь по похожим темам, чтобы найти возможные нерешённые случаи. Вот хороший пример того, как такие ситуации могут даже привести к юридическим проблемам из-за того, что загруженные пользователями файлы не становятся «сиротами» и не удаляются навсегда, как должно быть:

Ещё одна похожая ситуация, датируемая 2016 годом:

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

Достаточно ли здесь оснований для настоящего отчёта об ошибке? Я всё ещё не исключаю возможной неправильной конфигурации с нашей стороны, но меня озадачивает отсутствие сообщений об ошибках, и всё остальное работает как часы. Я потратил всё больше дней на устранение неполадок и тестирование, в процессе получив больше знаний о Discourse и его компонентах, поэтому считаю, что при некотором руководстве смогу помочь выяснить, есть ли какая-то деталь в особом случае, вызывающая это странное поведение. Надеюсь, нормально обратиться к @zogstrip на этом этапе?

Для временного решения возможно ли вручную переместить все загрузки в директорию «тумбы» (tombstone) и использовать методы восстановления загрузок, чтобы вернуть обратно в правильные директории только те файлы, которые не являются сиротами? Я сегодня пытался сделать это, но команда rake uploads:recover_from_tombstone не восстановила ни одного файла. Не указывает ли это на более серьёзную проблему с записями загрузок в базе данных?

Здравствуйте. У меня возникла та же или схожая проблема: не могу понять, почему файлы не удаляются. У кого-нибудь ещё до сих пор возникает эта проблема?
Я выполнил несколько SQL-запросов, и оказалось, что «застрявшие» ссылки на загрузки относятся исключительно к черновикам, но я проверил свои черновики и черновики других пользователей — их нет. Таблицы черновиков пусты.
Очистка ссылок на «сиротские» файлы включена, а настройки установлены на как можно более быстрое удаление таких ссылок.
Я приложил SQL-запрос.

SELECT 
    uploads.original_filename,
    ROUND(uploads.filesize / 1000000.0, 2) AS size_in_mb,
    uploads.extension,
    uploads.created_at,
    uploads.url,
    upload_references.upload_id,
    upload_references.target_id,
    upload_references.target_type,
    upload_references.created_at,
    upload_references.updated_at
FROM upload_references
JOIN uploads ON uploads.id = upload_references.upload_id
ORDER BY uploads.filesize DESC
LIMIT 250

sql.csv (46,1 КБ)

Это происходит с момента установки форума. Даже когда не было установлено никаких пользовательских тем или плагинов.
Даже старый логотип форума, который я загружал несколько раз (первый когда-либо загруженный файл), всё ещё числится как черновик и находится в папке загрузок. :man_facepalming:
Теоретически я мог бы отфильтровать все ссылки на загрузки по типу цели (target_type) для черновиков, удалить их из базы данных… и позволить задачам Sidekiq выполнить очистку (я прав?).
Но я использую собственную установку и довольно новичок в Discourse, поэтому лучше спросить здесь…
Это было бы обходным решением, но остаётся вопрос: почему это происходит?

Надеюсь, кто-нибудь даст советы — моё дисковое пространство растёт экспоненциально :smile:

Да, у нас тоже всё ещё есть эта проблема.

Я бы очень хотел как-то решить её: на нашем форуме загружается много файлов, но лишь небольшая часть из них требует долгосрочного хранения, из-за чего тратится много дискового пространства. Будем признательны за любые предложения по устранению неполадок.

Меня интересует это как временное решение, если оно практично. :thinking:

Я установил форум 2 недели назад, и эта проблема наблюдается с самого начала. Похоже на какой-то баг.
Можете ли вы выполнить тот же SQL-запрос и проверить, есть ли множество «застрявших» ссылок на черновики? Это легко увидеть: у меня их десятки, а в таблице drafts — всего 2 или 3 реальных черновика. Похоже, что ссылки не удаляются после редактирования (когда черновик перестает быть таковым, но ссылка в базе данных остается, например, при каждом редактировании поста).

Мне нужно понять, как удалить запись ссылки из базы данных. Сначала удалю ссылки для одного файла, а затем проверю, работает ли задача очистки.
Не знаю, насколько это безопасно, но эти бесчисленные записи Drafts кажутся мне ошибочными.

Я могу предоставить логи сотрудникам/разработчикам, но я новичок в Discourse и не знаю, какие именно файлы логов будут полезны.

РЕДАКТИРОВАНИЕ:
Я пытаюсь разобраться в структуре базы данных и понять, можно ли удалить эти записи загрузок без дальнейших проблем (не хочу нарушить важные связи в БД). Также я не понимаю, что именно такое draft_sequences.
Но мне сначала нужно клонировать свой продакшн-форум на локальную виртуальную машину, только тогда я смогу протестировать…

Ещё одна актуальная тема. Я написал там, так как не знал о существовании этого обсуждения.

Полагаю, единственный способ действительно удалить изображение автоматически — это вручную вырезать его из поста перед удалением самого поста. Но я не уверен на сто процентов, что это тоже работает. У меня настройки очистки такие же, как у вас (но я использую совместимое с S3 хранилище), и могу подтвердить: изображения никогда не удаляются, если есть только один пост, содержащий это изображение (несколько постов могут содержать одно и то же изображение; вероятно, это касается также аватаров и баннеров пользователей).

Я использую это решение для поиска, чтобы проверить, используется ли изображение в других постах. Оно было предоставлено @RGJ:

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

Ранее у меня был случай, когда спам-контент требовал срочного удаления через несколько аккаунтов. Это было очень стрессово: пришлось бороться с этим и убедиться, что всё удалено полностью (все оригинальные файлы, оптимизированные версии, кэш CDN, посты, аватары, баннеры пользователей и т. д.).

Я сделал предложение по этой функции, так как считаю, что это было бы очень полезно. Если это будет реализовано и вместе с этим автоматически будет очищаться контент из удалённых постов, то, думаю, будут покрыты все случаи, и всё можно будет обрабатывать без доступа по SSH.