Skip to content

Commit

Permalink
Worked on Retyrable Batch Failure in TrackEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
Gaurav Kochar committed Nov 1, 2024
1 parent bf47bce commit 87fffe7
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 14 deletions.
7 changes: 4 additions & 3 deletions packages/destination-actions/src/destinations/braze/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JSONLikeObject, ModifiedResponse, MultiStatusResponse, omit } from '@segment/actions-core'
import { ErrorCodes, JSONLikeObject, ModifiedResponse, MultiStatusResponse, omit } from '@segment/actions-core'
import { IntegrationError, RequestClient, removeUndefined } from '@segment/actions-core'
import dayjs from 'dayjs'
import { Settings } from './generated-types'
Expand All @@ -8,6 +8,7 @@ import { Payload as TrackPurchasePayload } from './trackPurchase/generated-types
import { Payload as UpdateUserProfilePayload } from './updateUserProfile/generated-types'
import { getUserAlias } from './userAlias'
import { HTTPError } from '@segment/actions-core'
import { ActionDestinationErrorResponseType } from '@segment/actions-core/destination-kittypes'
type DateInput = string | Date | number | null | undefined
type DateOutput = string | undefined | null

Expand Down Expand Up @@ -575,7 +576,7 @@ async function handleBrazeAPIResponse(

multiStatusResponse.setErrorResponseAtIndex(indexInOriginalPayload, {
status: 400,
errortype: 'BAD_REQUEST',
errortype: 'BAD_REQUEST' as keyof typeof ErrorCodes,
errormessage: error.type,
sent: payloads[indexInOriginalPayload],
body: error.type
Expand Down Expand Up @@ -610,7 +611,7 @@ async function handleBrazeAPIResponse(
(error?.response as ModifiedResponse<BrazeTrackUserAPIResponse>)?.data?.message ?? error.message,
sent: payloads[i],
body: parsedErrors[i].size > 0 ? Array.from(parsedErrors[i]).join(', ') : undefined
})
} as ActionDestinationErrorResponseType)
}
} else {
// Bubble up the error and let Actions Framework handle it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ describe('MultiStatus', () => {
createTestEvent({
type: 'track',
timestamp
}),
//Event with invalid Email
createTestEvent({
type: 'track',
timestamp,
properties: {
email: '[email protected]',
list_id: '123'
}
})
]

Expand All @@ -116,6 +125,13 @@ describe('MultiStatus', () => {
errormessage: 'One of External ID, Anonymous ID, Phone Number or Email is required.',
errorreporter: 'DESTINATION'
})
// The third event fails as pre-request validation fails for having invalid email
expect(response[2]).toMatchObject({
status: 400,
errortype: 'PAYLOAD_VALIDATION_FAILED',
errormessage: 'Email format is invalid.Please ensure it follows the standard format',
errorreporter: 'DESTINATION'
})
})

it('should successfully handle a batch of events with failure response from Klaviyo API', async () => {
Expand All @@ -127,7 +143,7 @@ describe('MultiStatus', () => {
status: 400,
code: 'invalid',
title: 'Invalid input.',
detail: 'Invalid email address',
detail: 'Invalid input',
source: {
pointer: '/data/attributes/events-bulk-create/data/0/attributes/email'
},
Expand All @@ -144,7 +160,7 @@ describe('MultiStatus', () => {
type: 'track',
timestamp,
properties: {
email: 'invalid_email'
email: '[email protected]'
}
}),
// Valid Event
Expand All @@ -167,18 +183,18 @@ describe('MultiStatus', () => {
expect(response[0]).toMatchObject({
status: 400,
errortype: 'BAD_REQUEST',
errormessage: 'Invalid email address',
errormessage: 'Invalid input',
sent: {
profile: {
email: 'invalid_email'
email: '[email protected]'
},
metric_name: 'Test Event',
properties: {
email: 'invalid_email'
email: '[email protected]'
},
time: timestamp
},
body: '{"id":"752f7ece-af20-44e0-aa3a-b13290d98e72","status":400,"code":"invalid","title":"Invalid input.","detail":"Invalid email address","source":{"pointer":"/data/attributes/events-bulk-create/data/0/attributes/email"},"links":{},"meta":{}}'
body: '{"id":"752f7ece-af20-44e0-aa3a-b13290d98e72","status":400,"code":"invalid","title":"Invalid input.","detail":"Invalid input","source":{"pointer":"/data/attributes/events-bulk-create/data/0/attributes/email"},"links":{},"meta":{}}'
})

// The second event fails as Braze API reports an error
Expand Down
28 changes: 23 additions & 5 deletions packages/destination-actions/src/destinations/klaviyo/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
IntegrationError,
PayloadValidationError,
MultiStatusResponse,
HTTPError
HTTPError,
ErrorCodes
} from '@segment/actions-core'
import { JSONLikeObject } from '@segment/actions-core'
import { API_URL, REVISION_DATE } from './config'
Expand All @@ -30,7 +31,8 @@ import { Payload } from './upsertProfile/generated-types'
import { Payload as TrackEventPayload } from './trackEvent/generated-types'
import dayjs from '../../lib/dayjs'
import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber'
import { eventBulkCreateRegex } from './properties'
import { emailRegex, eventBulkCreateRegex } from './properties'
import { ActionDestinationErrorResponseType } from '@segment/actions-core/destination-kittypes'

const phoneUtil = PhoneNumberUtil.getInstance()

Expand Down Expand Up @@ -480,7 +482,10 @@ export async function sendBatchedTrackEvent(request: RequestClient, payloads: Tr
try {
await request(`${API_URL}/event-bulk-create-jobs/`, {
method: 'POST',
json: payloadToSend
json: payloadToSend,
headers: {
revision: '2024-10-15'
}
})
} catch (err) {
if (err instanceof HTTPError) {
Expand Down Expand Up @@ -532,6 +537,16 @@ function validateAndPreparePayloads(payloads: TrackEventPayload[], multiStatusRe
payload.profile.phone_number = validPhoneNumber
delete payload?.profile?.country_code
}
if (email) {
if (!emailRegex.test(email)) {
multiStatusResponse.setErrorResponseAtIndex(originalBatchIndex, {
status: 400,
errortype: 'PAYLOAD_VALIDATION_FAILED',
errormessage: 'Email format is invalid.Please ensure it follows the standard format'
})
return
}
}

const profileToAdd = constructBulkCreateEventPayload(payload)
filteredPayloads.push(profileToAdd as JSONLikeObject)
Expand Down Expand Up @@ -599,14 +614,17 @@ function handleKlaviyoAPIErrorResponse(
errormessage: error.detail,
sent: payloads[indexInOriginalPayload],
body: JSON.stringify(error)
})
} as ActionDestinationErrorResponseType)
invalidIndexSet.add(indexInOriginalPayload)
}
})

for (const index of validPayloadIndicesBitmap) {
if (!invalidIndexSet.has(index)) {
multiStatusResponse.setSuccessResponseAtIndex(index, {
multiStatusResponse.setErrorResponseAtIndex(index, {
errormessage:
"This event wasn't delivered because of few bad events in the same batch to Klaviyo. This will be retried",
errortype: 'RETRYABLE_BATCH_FAILURE' as keyof typeof ErrorCodes,
status: 429,
sent: payloads[index],
body: 'Retry'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,5 @@ export const country_code: InputField = {
}
}
export const eventBulkCreateRegex = /\/data\/attributes\/events-bulk-create\/data\/(\d+)/
export const emailRegex =
/^(?!.*\.\.)(?!.*\.$)(?!.*@{2,})(?!.*@\.)(?!.*\.$)(?=.{1,256})[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/

0 comments on commit 87fffe7

Please sign in to comment.