Bulk Process Emails is client-driven, so large self-hosted backfills can't run to completion
Self-hosted, ghcr.io/elie222/inbox-zero:latest, standard compose stack. I'm backfilling rules across a 26k message Outlook inbox and hit a scale limit. Before I build anything I wanted to check whether you'd be open to moving bulk processing server side.
The loop in apps/web/app/(app)/[emailAccountId]/assistant/bulk-run.ts runs in the
browser. It pages /api/threads with nextPageToken, filters on thread.plan, and
awaits runAiRules for each batch of 25, feeding the client side ai-queue store. I can
see useBeforeUnload(isBusy) is there, so I know this is by design rather than an
oversight.
At a few hundred emails that's fine. At my volume it isn't:
- sustained throughput is about 5 to 6 messages a minute
- 26k messages comes out around 70 hours
- that's 70 hours of a tab staying open and a machine staying awake
I measured it with a 10 second sampler watching ExecutedRule inserts, "Fetching message
for rule execution" log lines, and TCP connections to the web container:
TIME ROWS DELTA FETCH CONN
12:20:12 3227 3 4 2 running
12:20:22 3228 1 3 0 tab closed
12:20:33 3228 0 2 0
12:20:43 3228 0 0 0
12:21:04 3228 0 0 0
12:22:07 3228 0 0 0 flat for 90s
12:28:46 3231 3 3 2 tab reopened, resumedRows froze the moment the connections dropped. The fetch lines drained to zero over the next 21 seconds, which is just the 30 second lookback window emptying. Reopening picked up from 3228 instead of restarting, so progress itself is durable. It's the driver that's ephemeral.
Would you take a PR moving this onto BullMQ? The pieces are already in place:
QUEUE_BACKEND=bullmq, a worker container, and existing queues for email-digest-all,
automation-jobs, digest-item-summarize and others. Rough shape I have in mind:
- a bulk run queue with one job per run, holding the paging loop that's currently in
bulk-run.ts - run state persisted so progress survives a disconnect and the UI can reattach
- pause, resume and stop become operations on the job rather than on a client store
BulkRunRulespolls run state instead of deriving progress from the localai-queue
I'm happy to design it properly and write it if that direction works for you. If you'd rather keep the client driven model I understand, and I'll just batch it locally by date range.
Source: elie222/inbox-zero