makeplane / makeplane/plane

🛠️ Improvement: crash-safe publication of project invitation tasks

Open
#9,814 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
59.6k
Forks
5.8k
Avg merge
1d 22h
Merged PRs (30d)
49

Description

Split out of #9812, which restores the project invitation endpoint from a guaranteed HTTP 500. This is the reliability gap underneath it, left out of that PR deliberately to keep the fix reviewable.

ProjectInvitationsViewset.create persists the invitations and then publishes a task per row:

created_invitations = ProjectMemberInvite.objects.bulk_create(
    project_invitations, batch_size=10, ignore_conflicts=True
)
for invitation in created_invitations:
    project_invitation.delay(...)

The rows are committed before the first delay(). If the broker is unreachable partway through, earlier invitations exist and have been emailed, later ones exist and have not, and the endpoint returns 500. A client that retries then re-sends invitations that already went out, since bulk_create(ignore_conflicts=True) will not recreate the row but the loop will publish for it again.

Worth covering:

  • persist an outbox record in the same transaction as the invitation, so the intent to send is committed atomically with the row
  • publish from the outbox with retries, rather than inline in the request
  • key idempotency on ProjectMemberInvite id so a retry cannot email the same invitee twice

WorkspaceInvitationsViewset has the same shape, so whatever lands here probably wants to apply there too.

Happy to pick this up if it is wanted, though the outbox table and where the publisher runs are design calls worth agreeing first.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at ProjectInvitationsViewset.create and compare its bulk_create and project_invitation.delay flow with WorkspaceInvitationsViewset. Agree the outbox table, publisher location, retry behavior, and ProjectMemberInvite idempotency approach before implementation. Done means invitation persistence and send intent are atomic, publishing retries safely, and request retries do not resend earlier invitations.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
backend-api-design, databases, distributed-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.