-
Notifications
You must be signed in to change notification settings - Fork 116
fix(subscription): resolve same-timestamp webhook ties by refetching latest state - #279
fix(subscription): resolve same-timestamp webhook ties by refetching latest state #279SumitKumar-17 wants to merge 1 commit into
Conversation
No actionable comments were generated in the recent review. 🎉
i️ Recent review info
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/fastify-app/src/test/subscriptionTimestampTieBreak.test.tspackages/sync-engine/src/stripeSync.ts
📝 Walkthrough
Summary by CodeRabbit
-
Tests
- Added comprehensive validation for subscription event handling when multiple updates occur within the same second.
-
Bug Fixes
- Enhanced subscription state synchronization to correctly handle rapid consecutive updates that occur within the same second. The system now ensures all changes are properly applied and the latest subscription status, billing cycle information, and related details remain accurate.
Walkthrough
A new test file validates tie-breaking behavior for Stripe subscription events occurring within the same second. The sync engine has been enhanced with a conflict-resolution mechanism that detects when two subscription updates share identical timestamps. When this condition is detected, the system refetches the latest subscription state from Stripe and applies it with a fresh timestamp, ensuring deterministic state handling during concurrent webhook processing.
Sequence Diagram(s)
sequenceDiagram
participant Webhook as Webhook Event
participant StripeSync as StripeSync
participant DB as Database
participant Stripe as Stripe API
Webhook->>StripeSync: processEvent (same timestamp)
StripeSync->>DB: upsert subscription
StripeSync->>DB: query subscriptions with same last_synced_at
DB-->>StripeSync: existing row found
StripeSync->>Stripe: subscriptions.retrieve()
Stripe-->>StripeSync: latest subscription state
StripeSync->>DB: upsert with fresh timestamp
DB-->>StripeSync: complete
StripeSync-->>Webhook: success
Comment @coderabbitai help to get the list of available commands and usage tips.
andrejpavlovic
commented
Feb 23, 2026
Shouldn't this be solved for all objects not just subscriptions? It just so happens that we found this issue with subscriptions, but it may apply to other models as well.
@andrejpavlovic Yeah i think you are correct. last_synced_at conflict protection is generic, so same-second tie behavior can affect any object. I suppose the repo maintainer of Supabase can continue here as this issue would require a lot of changes
jherbkersman
commented
May 1, 2026
The if (refetched || upsertedSubscriptions.length > 0) return short-circuit on upsertedSubscriptions.length > 0 looks intended but won't work as written — upsertManyWithTimestampProtection builds an INSERT ... ON CONFLICT DO UPDATE ... WHERE ... with no RETURNING clause, so its returned rows array is always empty regardless of whether the update applied. So that branch never short-circuits in practice; the post-upsert SELECT runs on every webhook.
...latest state (#268)
What kind of change does this PR introduce?
Bug fix, feature, docs update, ...
What is the current behavior?
Please link any relevant issues here.
What is the new behavior?
Feel free to include screenshots if it includes visual changes.
Additional context
Add any other context or screenshots.