mirror of
https://github.com/BillyOutlast/posthog.git
synced 2026-02-04 03:01:23 +01:00
fix(ingestion): retry on distinct id fk constraint failure (#38977)
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
PersonMergeLimitExceededError,
|
||||
PersonMergeRaceConditionError,
|
||||
PersonMergeResult,
|
||||
SourcePersonHasDistinctIdsError,
|
||||
SourcePersonNotFoundError,
|
||||
TargetPersonNotFoundError,
|
||||
mergeError,
|
||||
@@ -211,7 +212,6 @@ export class PersonMergeService {
|
||||
this.context.updateIsIdentified = true
|
||||
|
||||
const otherPerson = await this.context.personStore.fetchForUpdate(teamId, otherPersonDistinctId)
|
||||
|
||||
const mergeIntoPerson = await this.context.personStore.fetchForUpdate(teamId, mergeIntoDistinctId)
|
||||
|
||||
// A note about the `distinctIdVersion` logic you'll find below:
|
||||
@@ -518,6 +518,19 @@ export class PersonMergeService {
|
||||
return mergeError(error)
|
||||
} else if (error instanceof PersonMergeLimitExceededError) {
|
||||
return mergeError(error)
|
||||
} else if (error.code === '23503') {
|
||||
// Foreign key constraint violation when attempting to delete the source person.
|
||||
// This occurs when a concurrent merge operation adds a distinct ID to the source person
|
||||
// after we've already moved the distinct IDs we knew about, but before the DELETE executes.
|
||||
// The retry mechanism will:
|
||||
// 1. Refresh the source person data to see all distinct IDs (including newly added ones)
|
||||
// 2. Move ALL distinct IDs to the target person
|
||||
// 3. Successfully delete the now-empty source person
|
||||
return mergeError(
|
||||
new SourcePersonHasDistinctIdsError(
|
||||
'Cannot delete source person due to concurrent distinct ID additions'
|
||||
)
|
||||
)
|
||||
} else {
|
||||
// Re-throw unexpected errors
|
||||
throw error
|
||||
@@ -660,7 +673,10 @@ export class PersonMergeService {
|
||||
|
||||
// Handle retryable errors
|
||||
if (attempt < maxRetries) {
|
||||
if (result.error instanceof SourcePersonNotFoundError) {
|
||||
if (
|
||||
result.error instanceof SourcePersonNotFoundError ||
|
||||
result.error instanceof SourcePersonHasDistinctIdsError
|
||||
) {
|
||||
const refreshedPerson = await this.refreshPersonData(
|
||||
sourceDistinctId,
|
||||
currentSourcePerson.id,
|
||||
|
||||
@@ -66,6 +66,18 @@ export class TargetPersonNotFoundError extends PersonMergePersonNotFoundError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error when source person cannot be deleted due to concurrent distinct ID additions.
|
||||
* This occurs when a concurrent merge operation adds a distinct ID to the person being
|
||||
* deleted, causing a foreign key constraint violation. The retry will refresh the person
|
||||
* data and move all distinct IDs (including the newly added ones) before attempting deletion.
|
||||
*/
|
||||
export class SourcePersonHasDistinctIdsError extends PersonMergePersonNotFoundError {
|
||||
constructor(message: string) {
|
||||
super(message, 'source')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a person merge operation
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user