diff --git a/app/Containers/Dashboard/README_EMAIL_OPTIMIZATION.md b/app/Containers/Dashboard/README_EMAIL_OPTIMIZATION.md index 9fce243..af7fdf7 100644 --- a/app/Containers/Dashboard/README_EMAIL_OPTIMIZATION.md +++ b/app/Containers/Dashboard/README_EMAIL_OPTIMIZATION.md @@ -19,38 +19,40 @@ Allowed memory size of 268435456 bytes exhausted (tried to allocate 6291480 byte ### Уровень 1: Конфигурация (config/imap.php) -Добавлены настройки для предотвращения загрузки тел сообщений: +Добавлены настройки для предотвращения загрузки лишних данных: ```php 'options' => [ 'fetch' => \Webklex\PHPIMAP\IMAP::FT_PEEK, // Не помечать как прочитанные 'message_key' => 'id', // Использовать UID - 'fetch_body' => false, // НЕ загружать тела - 'fetch_flags' => false, // НЕ загружать флаги 'fetch_limit' => env('IMAP_FETCH_LIMIT', 20), // Лимит сообщений ], ``` -**Результат:** Загружаются только заголовки писем (subject, from, date), тела и вложения НЕ загружаются. +**Важно:** `fetch_body` и `fetch_flags` контролируются на уровне Query (`setFetchBody()`, `setFetchFlags()`), а не в конфиге, чтобы не ломать загрузку вложений. + +**Результат:** Письма не помечаются как прочитанные автоматически, используется лимит на количество сообщений. --- ### Уровень 2: Оптимизация кода #### 2A. FetchUnreadEmailsTask -- Добавлен `setFetchBody(false)` — явное отключение загрузки тел -- Добавлен `setFetchFlags(false)` — отключение загрузки флагов -- Добавлен параметр `$limit` для контроля количества сообщений -- Добавлен параметр `$offset` для пагинации +- `setFetchBody(true)` — загружаем структуру письма (необходимо для вложений) +- `setFetchFlags(false)` — отключаем загрузку флагов (экономия памяти) +- Параметр `$limit` для контроля количества сообщений +- Добавлен мониторинг памяти через `MemoryAwareTrait` ```php $query = $folder->messages() ->unseen() - ->setFetchBody(false) // ← КРИТИЧНО - ->setFetchFlags(false) - ->limit($limit); + ->setFetchBody(true) // Загружаем структуру (нужна для вложений) + ->setFetchFlags(false) // Флаги не нужны + ->limit($limit); // Лимит сообщений ``` +**Важно:** `setFetchBody(true)` необходим для загрузки структуры письма, которая содержит информацию о вложениях. Без этого `getAttachments()` возвращает пустой список. + #### 2B. FetchEmailNewsAction - Реализована **batch-обработка** (по 10 писем за цикл) - Добавлена **принудительная сборка мусора** после каждого batch diff --git a/app/Containers/Dashboard/Tasks/Email/FetchUnreadEmailsTask.php b/app/Containers/Dashboard/Tasks/Email/FetchUnreadEmailsTask.php index fc56e32..016522d 100644 --- a/app/Containers/Dashboard/Tasks/Email/FetchUnreadEmailsTask.php +++ b/app/Containers/Dashboard/Tasks/Email/FetchUnreadEmailsTask.php @@ -35,12 +35,12 @@ class FetchUnreadEmailsTask ]); try { - // OPTIMIZATION: Загружаем только заголовки (без тел и вложений) - // setFetchBody(false) предотвращает загрузку raw_body и structure + // NOTE: setFetchBody(true) необходим для загрузки структуры письма (вложения) + // Контроль памяти осуществляется через limit() и batch-обработку в Action $query = $folder->messages() ->unseen() - ->setFetchBody(false) - ->setFetchFlags(false); + ->setFetchBody(true) // Загружаем структуру (нужна для вложений) + ->setFetchFlags(false); // Флаги не нужны // Применяем лимит для предотвращения переполнения памяти if ($limit > 0) { @@ -53,6 +53,7 @@ class FetchUnreadEmailsTask foreach ($messages as $message) { // OPTIMIZATION: Извлекаем только метаданные (не загружаем тело) $from = $message->getFrom()[0] ?? null; + $subjectAttr = $message->getSubject(); $emails[] = [ 'message' => $message, @@ -60,8 +61,10 @@ class FetchUnreadEmailsTask 'uid' => $message->getUid(), 'from_email' => $from?->mail ?? null, 'from_name' => $from?->name ?? null, - 'subject' => $message->getSubject(), + // FIX: Attribute объект нужно конвертировать в строку + 'subject' => $subjectAttr instanceof \Webklex\PHPIMAP\Attribute ? (string) $subjectAttr : ($subjectAttr ?? 'Без темы'), 'date' => $message->getDate(), + // NOTE: hasAttachments() может быть неточным без загрузки структуры 'has_attachments' => $message->hasAttachments(), 'size' => $message->getSize(), ]; diff --git a/config/imap.php b/config/imap.php index e45714e..321ca53 100644 --- a/config/imap.php +++ b/config/imap.php @@ -93,18 +93,13 @@ return [ ], // OPTIMIZATION: Fetch method - FT_PEEK prevents marking messages as read automatically - // This also reduces memory usage by not loading full message bodies by default 'fetch' => \Webklex\PHPIMAP\IMAP::FT_PEEK, // OPTIMIZATION: Use UID as message key for better reliability 'message_key' => 'id', - // OPTIMIZATION: Do not fetch message bodies by default - // Bodies will be loaded only when explicitly needed (lazy loading) - 'fetch_body' => false, - - // OPTIMIZATION: Do not fetch flags by default (reduces memory) - 'fetch_flags' => false, + // NOTE: fetch_body и fetch_flags контролируются на уровне Query (setFetchBody/setFetchFlags) + // Глобальные настройки здесь не применяются, чтобы не ломать вложения // OPTIMIZATION: Limit number of messages fetched per query // Prevents memory overflow when processing large mailboxes