sync-v2 step 1: worker roles + interactive/bulk queue split

- config: WORKER_ROLE (sync|jobs|all), INTERACTIVE_CONCURRENCY, BULK_CONCURRENCY.
- queue: named queues (interactive/bulk) + enqueue_job() router; sync_bootstrap
  goes to bulk, all other jobs to interactive.
- workers.run: single entrypoint; role=jobs runs both arq consumers (per-queue
  timeout/concurrency), role=sync runs the supervisor, all=both (dev default).
- docker-compose: worker-sync + worker-jobs services (shared image, nofile
  ulimit); backend/Dockerfile; Makefile worker/worker-sync/worker-jobs targets.
- tests repointed to app.queue.get_arq_pool; supervisor behavior unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 19:53:31 +02:00
co-authored by Claude Opus 4.8
parent 9cb946f75d
commit e0a45c5a46
18 changed files with 262 additions and 102 deletions
+2 -6
View File
@@ -34,9 +34,7 @@ async def _ensure_drafts_folder(provider: Any, account: Account, user_id: uuid.U
uidvalidity = next((r.uidvalidity for r in remote if r.path == path), 0)
async with session_scope() as session:
existing = await session.scalar(
select(Mailbox).where(
Mailbox.account_id == account.id, Mailbox.special_use == "drafts"
)
select(Mailbox).where(Mailbox.account_id == account.id, Mailbox.special_use == "drafts")
)
if existing is not None:
return existing.path
@@ -72,9 +70,7 @@ async def push_draft_to_imap_job(ctx: dict[str, Any], draft_id: str) -> None:
attachments = await load_attachments(session, user_id, draft)
_, sent_raw, _, _ = build_mime(account, draft, reply_to, attachments)
drafts_mb = await session.scalar(
select(Mailbox).where(
Mailbox.account_id == account.id, Mailbox.special_use == "drafts"
)
select(Mailbox).where(Mailbox.account_id == account.id, Mailbox.special_use == "drafts")
)
drafts_path = drafts_mb.path if drafts_mb else None
account_obj = account