Skip to content

fix(background): avoid WorkOS org slug upserts#2925

Merged
tgmendes merged 1 commit into
mainfrom
fix-duplicate-key-violation-error-workos-processor-IP5a
May 20, 2026
Merged

fix(background): avoid WorkOS org slug upserts#2925
tgmendes merged 1 commit into
mainfrom
fix-duplicate-key-violation-error-workos-processor-IP5a

Conversation

@tgmendes
Copy link
Copy Markdown
Contributor

@tgmendes tgmendes commented May 19, 2026

Why?

WorkOS organization sync was failing with duplicate key value violates unique constraint "organization_metadata_slug_key". The upsert had ON CONFLICT (id) DO UPDATE but no protection against the separate slug unique index — when an event updated an org's name, the resulting slug could collide with a sibling row's existing slug and the whole event would fail (and retry forever).

What?

Switched from blind upsert to fetch-then-write. Pure INSERT on the create path, pure UPDATE on the update path, slug never touched after initial creation.

Resolution flow for organization create/update events:

  • Look up by workos_id. If found → update.
  • Otherwise, if external_id is set → look up by it (Gram org ID = external_id). If found → update; if not → INSERT a new row using external_id as the Gram ID.
  • Otherwise (no external_id), derive a deterministic Gram org ID via UUIDv5 from the WorkOS org ID, INSERT locally, then push that ID back to WorkOS as the external_id after the local transaction commits. Ordering ensures the remote external_id never points at a row that failed to persist. If the WorkOS write fails we log and rely on the next event to retry.

Also added a ShouldProcessEvent guard (event-ID lexicographic compare on ULIDs, falling back to workos_updated_at) so duplicate/out-of-order events from reconcile-overlap or backfill replay don't rewind state.

Concurrency considerations

  • Per-WorkOS-org workflows are serialized via Temporal SignalWithStartWorkflow + USE_EXISTING, so same-org events never race.
  • Cross-org create race (two events resolving to the same Gram org ID): the second INSERT fails with a PK conflict, the activity returns the error, Temporal retries, and the retry resolves to the update path.
  • Cross-org slug race (two different orgs slugifying to the same base): protected by pg_advisory_xact_lock(hashtext(slug)) taken before FindUnique, so concurrent inserts on the same base slug serialize.
  • Concurrency vs non-WorkOS writers (dashboard rename, signup flow, etc.) is
    NOT serialized by Temporal — only WorkOS sync vs WorkOS sync is. Known
    consequences:
    • Local UPDATE racing a WorkOS UPDATE: last writer wins. ShouldProcessEvent
      only de-dups WorkOS events against the cursor; it doesn't observe local writes.
    • Local INSERT racing a WorkOS INSERT on the same derived ID: second INSERT
      fails with PK conflict and Temporal retries into the update path.
    • Local INSERT racing a WorkOS INSERT on the same slug: advisory lock is
      WorkOS-side only; PG slug unique violation triggers retry + suffix.

@tgmendes tgmendes requested a review from a team as a code owner May 19, 2026 16:17
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 19, 2026

⚠️ No Changeset found

Latest commit: 5614dbb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gram-docs-redirect Ready Ready Preview, Comment May 20, 2026 9:53am

Request Review

@tgmendes
Copy link
Copy Markdown
Contributor Author

@claude review once

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, comment @claude review on this pull request to trigger a review.

@claude
Copy link
Copy Markdown

claude Bot commented May 19, 2026

Claude encountered an error after 0s —— View job


I'll analyze this and get back to you.

@github-actions github-actions Bot added the preview Spawn a preview environment label May 19, 2026
@speakeasybot
Copy link
Copy Markdown
Collaborator

speakeasybot commented May 19, 2026

🚀 Preview Environment (PR #2925)

Preview URL: https://pr-2925.dev.getgram.ai

Component Status Details Updated (UTC)
✅ Database Ready Existing database reused 2026-05-20 10:56:40.
✅ Images Available Container images ready 2026-05-20 10:55:36.

Gram Preview Bot

@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 474fb08 to b2c7a84 Compare May 19, 2026 16:29
@blacksmith-sh

This comment has been minimized.

@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from b2c7a84 to 973e024 Compare May 19, 2026 16:35
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 973e024 to 6f61d54 Compare May 19, 2026 16:40
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 6f61d54 to b69fc47 Compare May 19, 2026 17:01
@blacksmith-sh

This comment has been minimized.

@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from b69fc47 to e676393 Compare May 19, 2026 17:13
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from e676393 to e50803e Compare May 19, 2026 17:40
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from e50803e to b3d985d Compare May 19, 2026 17:46
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from b3d985d to 7555541 Compare May 19, 2026 17:59
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 7555541 to c090f4c Compare May 19, 2026 18:14
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from c090f4c to 7ac0c77 Compare May 20, 2026 09:08
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 7ac0c77 to f0d332b Compare May 20, 2026 09:18
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from f0d332b to 33010cc Compare May 20, 2026 09:24
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 33010cc to 2aee063 Compare May 20, 2026 09:31
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 2aee063 to a391c21 Compare May 20, 2026 09:33
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from a391c21 to 2436ad2 Compare May 20, 2026 09:40
@tgmendes tgmendes force-pushed the fix-duplicate-key-violation-error-workos-processor-IP5a branch from 2436ad2 to 5614dbb Compare May 20, 2026 09:53
@tgmendes tgmendes enabled auto-merge May 20, 2026 10:17
@tgmendes tgmendes added this pull request to the merge queue May 20, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks May 20, 2026
@tgmendes tgmendes added this pull request to the merge queue May 20, 2026
Merged via the queue into main with commit 360c795 May 20, 2026
33 checks passed
@tgmendes tgmendes deleted the fix-duplicate-key-violation-error-workos-processor-IP5a branch May 20, 2026 10:58
@github-actions github-actions Bot locked and limited conversation to collaborators May 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

preview Spawn a preview environment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants