Async Batch Pipeline - Add guardrails for SFMC result API - #3972
Async Batch Pipeline - Add guardrails for SFMC result API#3972sayan-das-in wants to merge 9 commits into
Conversation
…tch-pipeline-sfmc
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds guardrails to the SFMC async poll flow so that inconsistent /status vs /results responses (empty/missing items) are treated as retryable, preventing misleading “FAILED with no details” outcomes and avoiding returning an empty multiStatusResponse.
Changes:
- Treat
/resultsresponses with missing/emptyitemsasRETRYABLE_ERRORand dropmultiStatusResponse. - Ensure
multiStatusResponseis removed when/resultsthrows after it was initialized. - Add unit tests covering both empty and missing
itemscases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/destination-actions/src/destinations/salesforce-marketing-cloud/asyncDataExtension/index.async.ts | Adds retryable classification + cleanup of multiStatusResponse for empty/missing /results items and error paths. |
| packages/destination-actions/src/destinations/salesforce-marketing-cloud/tests/asyncDataExtension.async.test.ts | Adds tests validating RETRYABLE_ERROR + absence of multiStatusResponse for inconsistent /status//results. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // SFMC's /status can report hasErrors on a job whose /results page comes back with zero | ||
| // (or a missing) items array -- a status/results inconsistency, not proof the job | ||
| // actually failed. Since we have no per-record detail to act on, treat it as retryable | ||
| // rather than a hard FAILED with no explanation. | ||
| if (!resultsResponse.data.items || resultsResponse.data.items.length === 0) { | ||
| logger?.warn?.(`SFMC async /status reported errors for job ${payload.jobId} but /results returned no items`) | ||
| delete response.multiStatusResponse | ||
| response.jobStatus = 'RETRYABLE_ERROR' |
| // rather than a hard FAILED with no explanation. | ||
| if (!resultsResponse.data.items || resultsResponse.data.items.length === 0) { | ||
| logger?.warn?.(`SFMC async /status reported errors for job ${payload.jobId} but /results returned no items`) | ||
| delete response.multiStatusResponse |
| if (!resultsResponse.data.items || resultsResponse.data.items.length === 0) { | ||
| logger?.warn?.(`SFMC async /status reported errors for job ${payload.jobId} but /results returned no items`) | ||
| delete response.multiStatusResponse | ||
| response.jobStatus = 'RETRYABLE_ERROR' | ||
| return response | ||
| } |
| // rather than a hard FAILED with no explanation. | ||
| if (!resultsResponse.data.items || resultsResponse.data.items.length === 0) { | ||
| logger?.warn?.(`SFMC async /status reported errors for job ${payload.jobId} but /results returned no items`) | ||
| delete response.multiStatusResponse |
| // The /results call above may have thrown after response.multiStatusResponse was already | ||
| // initialized to an empty (but truthy) instance -- discard it so callers don't mistake | ||
| // "we never got any per-record data" for a real, if empty, multi-status result. | ||
| delete response.multiStatusResponse |
| expect(response.multiStatusResponse?.successCount).toBe(0) | ||
| }) | ||
|
|
||
| it('should return RETRYABLE_ERROR (not FAILED) when /status reports errors but /results returns zero items', async () => { |
| expect(response.jobStatus).toBe('RETRYABLE_ERROR') | ||
| expect(response.multiStatusResponse).toBeUndefined() | ||
| }) | ||
|
|
The SFMC
resultAPI can respond with empty status under load conditions. This change classifies those cases with retryable errors so that the orchestration layer can retry the status check again.Testing
Testing completed successfully in Staging with a 500k audience size.
Security Review
Please ensure sensitive data is properly protected in your integration.
type: 'password'New Destination Checklist
verioning-info.tsfile. example