Background inbox sync re-sends and re-renders every loaded message every 30 s, freezing the tab with several accounts

オープン
#13,809 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@gvansanden がすでに取り組んでいます。

2026年10月19日 から。

  • #13907 @gvansanden による — オープン

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
56/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, php

調査の方向性

Start with lib/Service/Sync/SyncService.php around the findChanged TODO and src/store/mainStore/actions.js around updateEnvelopeMutation; also inspect src/App.vue where syncInboxes() runs. Check existing sync tests and run the relevant server and client tests. Done means unchanged messages are not repeatedly returned or trigger list re-renders, while real flag or tag changes still update correctly.

索引モデルが issue の本文から書いたものです。

説明

1. to develop enhancement performance 🚀
Steps to reproduce
  1. Add several IMAP accounts to one user (I have 7, all on the same Dovecot server).
  2. Open Mail in the browser and leave it open (worse on "All inboxes" or after scrolling back through a list).
  3. Watch the tab every 30 seconds while the background inbox sync runs.
Expected behavior

When nothing changed on the server, the periodic background sync should send back (almost) nothing, and the UI should not re-render the message list.

Actual behavior

Every 30 s the tab freezes for a moment (the browser's loading indicator shows) and becomes responsive again as soon as the sync finishes.

The server side is fast. I logged the requests at the reverse proxy: every 30 s there is one POST /apps/mail/api/mailboxes/{id}/sync per account inbox, all fired at once, each answered in 0.2–0.6 s. However, every response for a given inbox has the same size on every poll (1.6–4.7 KB gzipped), even when nothing changed.

The cause seems to be in the code:

  1. Server: every known message is always returned as "changed".
    lib/Service/Sync/SyncService.php L146–L150

    // TODO: $changed = $this->messageMapper->findChanged($account, $mailbox, $uids);
    ...
    $changedIds = $knownIds;
    

    So changedMessages contains every envelope the client already has loaded, on every sync.

  2. Client: each "changed" envelope gets new flags / tags objects, even when they are identical.
    src/store/mainStore/actions.js L955 and L2111

    updateEnvelopeMutation({ envelope }) {
        ...
        Vue.set(existing, 'flags', envelope.flags)
        Vue.set(existing, 'tags', envelope.tags)
    }
    

    Because these are always new objects, Vue sends change notifications for every loaded envelope and re-renders the list.

  3. This runs for every account inbox every 30 s (src/App.vue L98, syncInboxes()). So the work grows with (number of accounts × loaded envelopes), and with several accounts the main thread blocks noticeably on every poll.

Suggested fix
  • Server: implement the findChanged TODO (e.g. use the CONDSTORE/flag-change UIDs the IMAP sync already gets) so only messages that really changed are returned.
  • Client (cheap, independent): in updateEnvelopeMutation, skip the Vue.set calls when flags / tags are unchanged. Comparing them first (e.g. JSON.stringify(old) !== JSON.stringify(new), since tags are already normalized to ID arrays) avoids re-rendering envelopes that did not change.

Possibly related: #13692 (memory blow-up on initial load). This report is about the steady-state 30 s poll after the app has loaded.

Mail app version

5.12.3

Nextcloud version

35.0.0 (Nextcloud All-in-One)

Mailserver or service

Dovecot 2.3.21 (mailcow)

Operating system

Linux (Debian 13)

PHP engine version

PHP 8.x (AIO image)

Web server

Apache (AIO) behind Caddy

Database

PostgreSQL

Additional info

The freezes stop as soon as each sync round finishes. Fewer accounts makes them shorter.

主要言語
JavaScript
スター
1.1k
フォーク
378
平均マージ
1日 12時間
マージ済み PR(30日)
116

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

nextcloud/mail のほかの issue

nextcloud/mail の issue をすべて見る

似ている issue

JavaScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。