Skip to content

Bulk Process Emails is client-driven, so large self-hosted backfills can't run to completion #3441

Description

@MrRussLuther

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, resumed

Rows 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
  • BulkRunRules polls run state instead of deriving progress from the local ai-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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions