Skip to content

feat(whatsapp-session): run linked WhatsApp accounts in a session service - #8538

Merged
404Wolf merged 1 commit into
mainfrom
wolf/wa-6-session-service
Oct 27, 2026
Merged

404Wolf merged 1 commit into
mainfrom
wolf/wa-6-session-service

Conversation

@404Wolf

@404Wolf 404Wolf commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Why

Each linked account needs one long-lived WhatsApp socket, owned by exactly
one process at a time, that pairs devices, keeps group rosters fresh,
ingests adopted-group traffic durably and dispatches the sends DSS
records. DSS talks to it only through MacroDB rows and NOTIFY; there is
no service-to-service HTTP.

How it works

supervisor ── pg_try_advisory_lock(account) ──▶ account task (begin_lease → epoch+1)
   ▲  LISTEN whatsapp_*                          │ whatsmeow client + PgWhatsAppStore
   │                                             ▼
 DSS NOTIFY (pairing/send/groups/changed)   SessionService (whatsapp_linked, in-process)

A stale epoch fails every write with Fenced and stops the account. On
SIGTERM a replica drains accounts in batches and announces releases.

What

  • services/whatsapp_session_service: supervisor, per-account runner,
    durable inbound (persisted before ACK, unadopted groups dropped), media
    import/upload, lock connection health, GET /health. Config through
    MacroConfig/Doppler only.
  • infra/stacks/whatsapp-session-service (ECS service and the KMS key for
    the store), the Doppler project entry, and Datadog monitors.
  • .github/services-config.json registers it with deploy_enabled: false
    and a bootstrap_pending note: it needs its Doppler project and keys
    (including WHATSAPP_SESSION_KMS_KEY_ID from the stack's first deploy)
    and an explicit go-ahead before anything deploys it.
  • Local stack: compose service, xtask_local inventory, env placeholders
    and LocalStack KMS; nix deploy list; generic deploy workflow choice.
  • SQLx cache entries; regenerated workspace-hack and closures.

Follow-ups

  • Create the Doppler project/keys and run the first stack deploy, then flip
    deploy_enabled (needs explicit approval).

Audit fixes

Audit security fixes in this layer: session-service logs and whatsmeow errors never carry JIDs.

Stack

WhatsApp linked devices, one layer per PR. Merge bottom-up; each PR is based on the one below it, so its diff is only its own layer. Layers 1-9 are wolf/whatsmeow-rs as of the split; layers 10-16 are the later work on that branch, regrouped by topic. The audit fixes are folded into the layers that own the code they fix. The schema is three migrations in its final shape: layer 4's 20261027061310_whatsapp_linked and 20261027061311_validate_entity_whatsapp_group_type, and layer 5's 20261027062649_whatsapp_store; no later layer adds a migration.

  1. feat(whatsmeow): port the whatsmeow linked-device client to Rust #8527 whatsmeow client port (merged)
  2. feat(whatsmeow-signal): implement whatsmeow's Signal protocol with libsignal #8534 Signal protocol + fake server (merged)
  3. feat(auth): record whether a user credential is a Macro API JWT #8535 API-JWT credential origin
  4. feat(whatsapp): add WhatsApp group entities and the linked-account API #8536 WhatsApp group entity + DSS API
  5. feat(whatsapp-store): store whatsmeow state encrypted in Postgres #8537 encrypted Postgres store
  6. feat(whatsapp-session): run linked WhatsApp accounts in a session service #8538 session service + infra ← this PR
  7. feat(sdk): add WhatsApp linked groups to the SDK #8539 SDK
  8. feat(web): link WhatsApp accounts and open shared WhatsApp groups #8540 web + desktop
  9. test(whatsapp): run the linked-device fleet end to end and document it #8541 end-to-end tests + docs
  10. feat(whatsmeow): trace connects, IQs and messages without leaking JIDs #8724 whatsmeow telemetry + error redaction
  11. feat(whatsapp): own groups personally, follow WhatsApp, push changes #8725 personal groups, live refresh, push, share by mention, NOTIFY traces
  12. feat(whatsapp): open WhatsApp groups in External as channel chats #8726 web: groups as channel conversations in External
  13. feat(whatsapp): list every chat, import history and fix sender identity #8727 sender identity, chat list, history import
  14. feat(whatsapp): import and render every WhatsApp message type #8728 every message type
  15. feat(whatsapp): add disappearing, community and direct chats to Macro #8729 disappearing, community and direct chats
  16. feat(whatsapp): list members in the side panel, wait quietly to import #8853 side-panel members, quiet waits to import

Previous: #8537 · Next: #8539

@404Wolf
404Wolf requested a review from a team as a code owner October 22, 2026 16:23
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
Walkthrough

[!WARNING]
Review details and warnings were omitted to fit the comment limit.

Priority: Normal

Merge Risk: Moderate · previous review 56aec

Fix the entity-constraint migration's lock scope, the restrictive send-row foreign keys, and the consent timestamp reset before merging. The service is not deployed yet, so these can be handled in this PR. The listener back-off and drain-bound issues are lower-impact follow-ups.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Title check Warning The title uses conventional-commit format and clearly describes the change, but it is 73 characters long and exceeds the 72-character limit. Shorten the title to 72 characters or fewer, for example: "feat(whatsapp-session): run linked accounts in a session service"
Passed Passed checks: 3 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The PR description explains the purpose and mechanism of the change: a WhatsApp session service that holds one long-lived socket per linked account using advisory-lock leases and epoch fencing, with D…
Full details: Description check

Explanation

The PR description explains the purpose and mechanism of the change: a WhatsApp session service that holds one long-lived socket per linked account using advisory-lock leases and epoch fencing, with DSS communicating through MacroDB rows and NOTIFY. It also lists the concrete contents (service, infra stack, Doppler entry, Datadog monitors, local stack, deploy config, SQLx cache) and the deploy_enabled:false gating. It is directly related to the changeset, so it is not off-topic or vague.

✨ Finishing Touches: 💡 1
⚔️ Resolve merge conflicts: 💡
  • Resolve merge conflict in branch wolf/wa-6-session-service
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 22, 2026 17:26
@404Wolf
404Wolf changed the base branch from wolf/wa-5-store to main October 22, 2026 18:24
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch 3 times, most recently from 1a973d2 to 2c715d9 Compare October 22, 2026 20:23
@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 22, 2026 21:24
@404Wolf
404Wolf changed the base branch from wolf/wa-5-store to main October 22, 2026 23:15
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 2c715d9 to 7791bcd Compare October 22, 2026 23:15
@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 22, 2026 23:57
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 7791bcd to ebf6690 Compare October 23, 2026 19:48
@404Wolf
404Wolf changed the base branch from wolf/wa-5-store to main October 23, 2026 19:48
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 56aec26 to 1abda91 Compare October 24, 2026 03:34
@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 24, 2026 05:11
@404Wolf
404Wolf changed the base branch from wolf/wa-5-store to main October 26, 2026 16:18
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 1abda91 to 56763ac Compare October 26, 2026 16:18
@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 26, 2026 17:45
@404Wolf
404Wolf changed the base branch from wolf/wa-5-store to main October 26, 2026 19:45
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 56763ac to f5801a5 Compare October 26, 2026 19:46
@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 26, 2026 21:11
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from f5801a5 to 49875b4 Compare October 27, 2026 01:10
@404Wolf
404Wolf force-pushed the wolf/wa-5-store branch 2 times, most recently from 0c9895a to dc3858e Compare October 27, 2026 09:34
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 49875b4 to 16f8538 Compare October 27, 2026 09:34
@404Wolf
404Wolf changed the base branch from wolf/wa-5-store to main October 27, 2026 09:35
@404Wolf 404Wolf closed this Oct 27, 2026
@404Wolf 404Wolf reopened this Oct 27, 2026
@404Wolf
404Wolf changed the base branch from main to wolf/wa-5-store October 27, 2026 10:41
@404Wolf
404Wolf force-pushed the wolf/wa-5-store branch 2 times, most recently from 5096d8c to fc93036 Compare October 27, 2026 11:20
Base automatically changed from wolf/wa-5-store to main October 27, 2026 11:40
…vice

Why:

Each linked account needs one long-lived WhatsApp socket, owned by exactly
one process at a time, that pairs devices, keeps group rosters fresh,
ingests adopted-group traffic durably and dispatches the sends DSS
records. DSS talks to it only through MacroDB rows and `NOTIFY`; there is
no service-to-service HTTP.

How it works:

```
supervisor ── pg_try_advisory_lock(account) ──▶ account task (begin_lease → epoch+1)
   ▲  LISTEN whatsapp_*                          │ whatsmeow client + PgWhatsAppStore
   │                                             ▼
 DSS NOTIFY (pairing/send/groups/changed)   SessionService (whatsapp_linked, in-process)
```

A stale epoch fails every write with `Fenced` and stops the account. On
SIGTERM a replica drains accounts in batches and announces releases.

What:

- `services/whatsapp_session_service`: supervisor, per-account runner,
  durable inbound (persisted before ACK, unadopted groups dropped), media
  import/upload, lock connection health, `GET /health`. Config through
  `MacroConfig`/Doppler only.
- `infra/stacks/whatsapp-session-service` (ECS service and the KMS key for
  the store), the Doppler project entry, and Datadog monitors.
- `.github/services-config.json` registers it with `deploy_enabled: false`
  and a `bootstrap_pending` note: it needs its Doppler project and keys
  (including `WHATSAPP_SESSION_KMS_KEY_ID` from the stack's first deploy)
  and an explicit go-ahead before anything deploys it.
- Local stack: compose service, `xtask_local` inventory, env placeholders
  and LocalStack KMS; nix deploy list; generic deploy workflow choice.
- SQLx cache entries; regenerated `workspace-hack` and closures.

Follow-ups:

- Create the Doppler project/keys and run the first stack deploy, then flip
  `deploy_enabled` (needs explicit approval).

Audit fixes:

Audit security fixes in this layer: session-service logs and whatsmeow errors never carry JIDs.
@404Wolf
404Wolf force-pushed the wolf/wa-6-session-service branch from 16f8538 to 71c9f41 Compare October 27, 2026 11:40
@404Wolf
404Wolf merged commit 0c73249 into main Oct 27, 2026
72 checks passed
@404Wolf
404Wolf deleted the wolf/wa-6-session-service branch October 27, 2026 12:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant