Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: salesforce v2 refactor #3773

Closed
wants to merge 14 commits into from
2 changes: 2 additions & 0 deletions src/v0/destinations/salesforce/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const SF_TOKEN_REQUEST_URL_SANDBOX = 'https://test.salesforce.com/services/oauth
const DESTINATION = 'Salesforce';
const OAUTH = 'oauth';
const LEGACY = 'legacy';
const SALESFORCE_OAUTH = 'SALESFORCE_OAUTH';

const mappingConfig = getMappingConfig(ConfigCategory, __dirname);

Expand All @@ -41,4 +42,5 @@ module.exports = {
DESTINATION,
OAUTH,
LEGACY,
SALESFORCE_OAUTH,
};
16 changes: 10 additions & 6 deletions src/v0/destinations/salesforce/networkHandler.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
const { proxyRequest, prepareProxyRequest } = require('../../../adapters/network');
const { processAxiosResponse } = require('../../../adapters/utils/networkUtils');
const { isHttpStatusSuccess } = require('../../util');
const { LEGACY } = require('./config');
const { salesforceResponseHandler } = require('./utils');

const responseHandler = (responseParams) => {
const { destinationResponse, destType, rudderJobMetadata } = responseParams;
const message = `Request for destination: ${destType} Processed Successfully`;
const { status } = destinationResponse;

salesforceResponseHandler(
destinationResponse,
'during Salesforce Response Handling',
rudderJobMetadata?.destInfo?.authKey,
LEGACY,
);
if (!isHttpStatusSuccess(status) && status >= 400) {
salesforceResponseHandler(
destinationResponse,
'during Salesforce Response Handling',
rudderJobMetadata?.destInfo?.authKey,
LEGACY,
);
}

// else successfully return status as 200, message and original destination response
return {
Expand Down
124 changes: 63 additions & 61 deletions src/v0/destinations/salesforce/utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
const { RetryableError, ThrottledError, AbortedError } = require('@rudderstack/integrations-lib');
const { handleHttpRequest } = require('../../../adapters/network');
const {
isHttpStatusSuccess,
getAuthErrCategoryFromStCode,
isDefinedAndNotNull,
} = require('../../util');
const { getAuthErrCategoryFromStCode } = require('../../util');
const Cache = require('../../util/cache');
const {
ACCESS_TOKEN_CACHE_TTL,
Expand All @@ -13,6 +9,7 @@
DESTINATION,
LEGACY,
OAUTH,
SALESFORCE_OAUTH,
} = require('./config');

const ACCESS_TOKEN_CACHE = new Cache(ACCESS_TOKEN_CACHE_TTL);
Expand All @@ -28,72 +25,74 @@
const salesforceResponseHandler = (destResponse, sourceMessage, authKey, authorizationFlow) => {
const { status, response } = destResponse;

// if the response from destination is not a success case build an explicit error
if (!isHttpStatusSuccess(status) && status >= 400) {
const matchErrorCode = (errorCode) =>
response && Array.isArray(response) && response.some((resp) => resp?.errorCode === errorCode);
if (status === 401 && authKey && matchErrorCode('INVALID_SESSION_ID')) {
if (authorizationFlow === OAUTH) {
const matchErrorCode = (errorCode) =>
shrouti1507 marked this conversation as resolved.
Show resolved Hide resolved
response && Array.isArray(response) && response.some((resp) => resp?.errorCode === errorCode);

const getErrorMessage = () => {
if (response && Array.isArray(response) && response[0]?.message?.length > 0) {
shrouti1507 marked this conversation as resolved.
Show resolved Hide resolved
return response[0].message;
}
return JSON.stringify(response);
};

switch (status) {
case 401:
if (authKey && matchErrorCode('INVALID_SESSION_ID')) {
if (authorizationFlow === OAUTH) {
throw new RetryableError(
`${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`,
500,
destResponse,
getAuthErrCategoryFromStCode(status),
);
}
ACCESS_TOKEN_CACHE.del(authKey);
throw new RetryableError(
`${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`,
500,
destResponse,
getAuthErrCategoryFromStCode(status),
);
}
// checking for invalid/expired token errors and evicting cache in that case
// rudderJobMetadata contains some destination info which is being used to evict the cache
ACCESS_TOKEN_CACHE.del(authKey);
throw new RetryableError(
`${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`,
500,
destResponse,
);
} else if (status === 403 && matchErrorCode('REQUEST_LIMIT_EXCEEDED')) {
// If the error code is REQUEST_LIMIT_EXCEEDED, you’ve exceeded API request limits in your org.
throw new ThrottledError(
`${DESTINATION} Request Failed - due to "REQUEST_LIMIT_EXCEEDED", (Throttled) ${sourceMessage}`,
destResponse,
);
} else if (
status === 400 &&
matchErrorCode('CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY') &&
(response?.message?.includes('UNABLE_TO_LOCK_ROW') ||
response?.message?.includes('Too many SOQL queries'))
) {
// handling the error case where the record is locked by another background job
// this is a retryable error
break;

case 403:
if (matchErrorCode('REQUEST_LIMIT_EXCEEDED')) {
throw new ThrottledError(
`${DESTINATION} Request Failed - due to "REQUEST_LIMIT_EXCEEDED", (Throttled) ${sourceMessage}`,
destResponse,
);
}
shrouti1507 marked this conversation as resolved.
Show resolved Hide resolved
break;

Check warning on line 65 in src/v0/destinations/salesforce/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/salesforce/utils.js#L65

Added line #L65 was not covered by tests

case 400:
if (
matchErrorCode('CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY') &&
(response?.message?.includes('UNABLE_TO_LOCK_ROW') ||
response?.message?.includes('Too many SOQL queries'))

Check warning on line 71 in src/v0/destinations/salesforce/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/salesforce/utils.js#L70-L71

Added lines #L70 - L71 were not covered by tests
) {
throw new RetryableError(

Check warning on line 73 in src/v0/destinations/salesforce/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/salesforce/utils.js#L73

Added line #L73 was not covered by tests
`${DESTINATION} Request Failed - "${response.message}", (Retryable) ${sourceMessage}`,
500,
destResponse,
);
}
break;

case 503:
case 500:
throw new RetryableError(
`${DESTINATION} Request Failed - "${response.message}", (Retryable) ${sourceMessage}`,
`${DESTINATION} Request Failed - due to "${getErrorMessage()}", (Retryable) ${sourceMessage}`,
500,
destResponse,
);
} else if (status === 503 || status === 500) {
// The salesforce server is unavailable to handle the request. Typically this occurs if the server is down
// for maintenance or is currently overloaded.
throw new RetryableError(
`${DESTINATION} Request Failed - due to "${
response && Array.isArray(response) && response[0]?.message?.length > 0
? response[0].message
: JSON.stringify(response)
}", (Retryable) ${sourceMessage}`,
500,

default:

Check warning on line 89 in src/v0/destinations/salesforce/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/salesforce/utils.js#L89

Added line #L89 was not covered by tests
// Default case: aborting for all other error codes
throw new AbortedError(

Check warning on line 91 in src/v0/destinations/salesforce/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/salesforce/utils.js#L91

Added line #L91 was not covered by tests
`${DESTINATION} Request Failed: "${status}" due to "${getErrorMessage()}", (Aborted) ${sourceMessage}`,
400,
destResponse,
);
}
// check the error message
let errorMessage = '';
if (response && Array.isArray(response)) {
errorMessage = response[0].message;
}
// aborting for all other error codes
throw new AbortedError(
`${DESTINATION} Request Failed: "${status}" due to "${
errorMessage || JSON.stringify(response)
}", (Aborted) ${sourceMessage}`,
400,
destResponse,
);
}
};

Expand Down Expand Up @@ -169,9 +168,12 @@
const collectAuthorizationInfo = async (event) => {
let authorizationFlow;
let authorizationData;
if (isDefinedAndNotNull(event.metadata?.secret)) {

const { destination, metadata } = event;
const { Name } = destination.DestinationDefinition;
if (Name === SALESFORCE_OAUTH) {
authorizationFlow = OAUTH;
authorizationData = getAccessTokenOauth(event.metadata);
authorizationData = getAccessTokenOauth(metadata);
} else {
authorizationFlow = LEGACY;
authorizationData = await getAccessToken(event);
Expand Down
16 changes: 10 additions & 6 deletions src/v0/destinations/salesforce_oauth/networkHandler.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
const { proxyRequest, prepareProxyRequest } = require('../../../adapters/network');
const { processAxiosResponse } = require('../../../adapters/utils/networkUtils');
const { isHttpStatusSuccess } = require('../../util');
const { OAUTH } = require('../salesforce/config');
const { salesforceResponseHandler } = require('../salesforce/utils');

const responseHandler = (responseParams) => {
const { destinationResponse, destType, rudderJobMetadata } = responseParams;
const message = `Request for destination: ${destType} Processed Successfully`;
const { status } = destinationResponse;

salesforceResponseHandler(
destinationResponse,
'during Salesforce Response Handling',
rudderJobMetadata?.destInfo?.authKey,
OAUTH,
);
if (!isHttpStatusSuccess(status) && status >= 400) {
salesforceResponseHandler(
destinationResponse,
'during Salesforce Response Handling',
rudderJobMetadata?.destInfo?.authKey,
OAUTH,
);
}

// else successfully return status as 200, message and original destination response
return {
Expand Down
Loading