Skip to content

STRATCONN-6127 - [Pendo Audiences] - handle 409 as 429 retries#3845

Open
joe-ayoub-segment wants to merge 1 commit into
mainfrom
pendo-audiences-concurrency-issue
Open

STRATCONN-6127 - [Pendo Audiences] - handle 409 as 429 retries#3845
joe-ayoub-segment wants to merge 1 commit into
mainfrom
pendo-audiences-concurrency-issue

Conversation

@joe-ayoub-segment

@joe-ayoub-segment joe-ayoub-segment commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Pendo's segment-visitor PATCH endpoint returns 409 "Operation in progress" when a write to a segment is already underway — a transient condition. Previously the destination surfaced this as a hard failure, so events were dropped instead of retried.

This PR maps a Pendo 409 to a RetryableError (429), so Segment's pipeline retries the request later (with backoff) once Pendo is no longer busy. The whole request is retried rather than failing individual items, since the single PATCH covering all visitors is what Pendo rejected.

Also in this change:

  • syncAudience now resolves add/remove from Segment's native audienceMembership (instead of reading the membership trait directly), throwing InvalidAudienceMembershipError when membership can't be determined.
  • Corrected the multistatus sent/body fields (sent = the input payload, body = the request sent to Pendo).
  • Unit tests cover the 409→429 retry path for both single and batch modes, plus the new validation behavior.

Testing

Unit tests updated.

e2e tests created which test the following:

  1. createAudience
  2. send single event X 2
  3. send batch events X 2
  4. getAudience
  5. teardown audience

These e2e tests are not yet in main as there core e2e code is not merged yet. The e2e tests are currently in this PR - #3829 - as well as a mirror copy of the pendo-audiences destination in this branch.

Stage testing required.

Security Review

Please ensure sensitive data is properly protected in your integration.

  • Reviewed all field definitions for sensitive data (API keys, tokens, passwords, client secrets) and confirmed they use type: 'password'

New Destination Checklist

  • Extracted all action API versions to verioning-info.ts file. example

@joe-ayoub-segment joe-ayoub-segment requested a review from a team as a code owner June 19, 2026 14:33
Copilot AI review requested due to automatic review settings June 19, 2026 14:33
@joe-ayoub-segment joe-ayoub-segment changed the title handle 409 as retries for pendo-audience destination [Pendo Audiences] - handle 409 as 429 retries Jun 19, 2026
@joe-ayoub-segment joe-ayoub-segment changed the title [Pendo Audiences] - handle 409 as 429 retries STRATCONN-6127 - [Pendo Audiences] - handle 409 as 429 retries Jun 19, 2026
@joe-ayoub-segment joe-ayoub-segment self-assigned this Jun 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the Pendo Audiences syncAudience action to better handle Pendo’s transient write conflicts by retrying on HTTP 409s (via a RetryableError surfaced as 429), and refactors membership resolution to use the core-provided audienceMembership signal instead of deriving it from traits/properties.

Changes:

  • Treats HTTP 409 responses from Pendo’s segment PATCH as retryable by throwing RetryableError(..., 429).
  • Switches add/remove decisioning to use audienceMembership (and removes the internal-only mapping fields previously used to infer membership).
  • Reworks/expands unit tests for single-event and batched Engage flows, including 409 retry behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/index.ts Wires audienceMembership into send() for single and batch execution.
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/generated-types.ts Removes now-unneeded payload fields used for membership inference.
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/functions.ts Implements 409→retry behavior and uses audienceMemberships to decide add/remove operations.
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/fields.ts Removes internal/hidden fields previously required to infer membership.
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/tests/perform.test.ts Deletes older tests superseded by newer Engage single/batch coverage.
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/tests/engage-single.test.ts Adds single-event tests including invalid membership and 409 retry.
packages/destination-actions/src/destinations/pendo-audiences/syncAudience/tests/engage-batch.test.ts Updates/extends batch tests, including track membership resolution and 409 retry.
packages/destination-actions/src/destinations/pendo-audiences/metadata.json Removed in this PR (should be regenerated/committed rather than deleted).

Comment on lines 119 to 124
if (isSuccess) {
msResponse.setSuccessResponseAtIndex(index, {
status: item.status,
body: p as unknown as JSONLikeObject,
sent: buildSent(item.operation, visitorId)
sent: p as unknown as JSONLikeObject,
body: buildPendoRequest(item.operation, [visitorId])
})
Comment on lines 10 to 15
'@path': '$.userId'
}
},
traitsOrProperties: {
label: 'Traits or Properties',
description: 'Traits or Properties object from the identify() or track() call emitted by Engage.',
type: 'object',
required: true,
unsafe_hidden: true,
default: {
'@if': {
exists: { '@path': '$.traits' },
then: { '@path': '$.traits' },
else: { '@path': '$.properties' }
}
}
},
segmentAudienceKey: {
label: 'Segment Audience Key',
description: 'Segment Audience Key. Used to determine whether the user is being added to or removed from the Pendo Segment.',
type: 'string',
required: true,
unsafe_hidden: true,
default: {
'@path': '$.context.personas.computation_key'
}
},
segmentAudienceId: {
label: 'Segment External Audience ID',
description: 'The External Audience ID from Segment, which maps to the Pendo Segment ID.',
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants