fix(background): avoid WorkOS org slug upserts#2925
Conversation
There was a problem hiding this comment.
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.
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@claude review once |
There was a problem hiding this comment.
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 encountered an error after 0s —— View job I'll analyze this and get back to you. |
🚀 Preview Environment (PR #2925)Preview URL: https://pr-2925.dev.getgram.ai
Gram Preview Bot |
474fb08 to
b2c7a84
Compare
This comment has been minimized.
This comment has been minimized.
b2c7a84 to
973e024
Compare
973e024 to
6f61d54
Compare
6f61d54 to
b69fc47
Compare
This comment has been minimized.
This comment has been minimized.
b69fc47 to
e676393
Compare
e676393 to
e50803e
Compare
e50803e to
b3d985d
Compare
b3d985d to
7555541
Compare
7555541 to
c090f4c
Compare
c090f4c to
7ac0c77
Compare
7ac0c77 to
f0d332b
Compare
f0d332b to
33010cc
Compare
33010cc to
2aee063
Compare
2aee063 to
a391c21
Compare
a391c21 to
2436ad2
Compare
2436ad2 to
5614dbb
Compare
Why?
WorkOS organization sync was failing with
duplicate key value violates unique constraint "organization_metadata_slug_key". The upsert hadON CONFLICT (id) DO UPDATEbut 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:
workos_id. If found → update.external_idis set → look up by it (Gram org ID = external_id). If found → update; if not → INSERT a new row usingexternal_idas the Gram ID.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 theexternal_idafter the local transaction commits. Ordering ensures the remoteexternal_idnever 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
ShouldProcessEventguard (event-ID lexicographic compare on ULIDs, falling back toworkos_updated_at) so duplicate/out-of-order events from reconcile-overlap or backfill replay don't rewind state.Concurrency considerations
SignalWithStartWorkflow+USE_EXISTING, so same-org events never race.pg_advisory_xact_lock(hashtext(slug))taken beforeFindUnique, so concurrent inserts on the same base slug serialize.NOT serialized by Temporal — only WorkOS sync vs WorkOS sync is. Known
consequences:
ShouldProcessEventonly de-dups WorkOS events against the cursor; it doesn't observe local writes.
fails with PK conflict and Temporal retries into the update path.
WorkOS-side only; PG slug unique violation triggers retry + suffix.