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

feat: move hubspot to transformer proxy to enable partial batch handling #3308

Merged
merged 32 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
722f3d1
feat: move hubspot to transformer proxy to enable partial batch handling
ItsSudip Apr 24, 2024
a09afd6
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Apr 26, 2024
3993401
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip May 21, 2024
d66755c
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip May 22, 2024
effc2e1
chore: refactor code
ItsSudip May 22, 2024
f622710
chore: add unit tests
ItsSudip May 24, 2024
8d428e8
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip May 24, 2024
43c1174
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip May 27, 2024
1b9c83b
chore: refactor code
ItsSudip May 27, 2024
0927f2a
chore: update error message
ItsSudip May 27, 2024
85de831
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jun 5, 2024
3d896d4
Merge branch 'develop' of github.com:rudderlabs/rudder-transformer in…
ItsSudip Jun 11, 2024
cded119
fix: update network handler for legacy api
ItsSudip Jun 12, 2024
a2852d7
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jun 12, 2024
4f1915f
chore: address comment
ItsSudip Jun 12, 2024
dfa4008
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jun 14, 2024
06d60ae
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jun 20, 2024
e87d031
chore: update failed tests
ItsSudip Jun 20, 2024
cc3c7c6
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jun 21, 2024
f88bb52
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jul 4, 2024
7eadc12
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jul 12, 2024
722bfbc
fix: update network handler
ItsSudip Jul 15, 2024
2fe5fbd
feat: add verification of single event
ItsSudip Jul 17, 2024
e1606a0
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jul 18, 2024
4d175c1
chore: resolve conflicts
ItsSudip Jul 22, 2024
571842c
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jul 23, 2024
cedb653
chore: resolve conflicts
ItsSudip Jul 30, 2024
653e25c
chore: add test cases
ItsSudip Jul 31, 2024
63c03e7
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jul 31, 2024
8246fcb
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Jul 31, 2024
e1ecb95
Merge branch 'develop' into feat.hs-handle-partial-error
ItsSudip Aug 5, 2024
f82f877
Merge branch 'hotfix/12082024' into feat.hs-handle-partial-error
ItsSudip Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions src/v0/destinations/hs/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const {
fetchFinalSetOfTraits,
getProperties,
validateDestinationConfig,
convertToResponseFormat,
} = require('./util');

const processSingleMessage = async (message, destination, propertyMap) => {
Expand Down Expand Up @@ -137,16 +138,32 @@ const processRouterDest = async (inputs, reqMetadata) => {
}),
);

const dontBatchTrueResponses = [];
const dontBatchFalseOrUndefinedResponses = [];
// segregating successRepList depending on dontbatch value
successRespList.forEach((successResp) => {
if (successResp.metadata?.dontBatch) {
dontBatchTrueResponses.push(successResp);
} else {
dontBatchFalseOrUndefinedResponses.push(successResp);
}
});

// batch implementation
let batchedResponseList = [];
if (successRespList.length > 0) {
if (destination.Config.apiVersion === API_VERSION.v3) {
batchedResponseList = batchEvents(successRespList);
batchedResponseList = batchEvents(dontBatchFalseOrUndefinedResponses);
} else {
batchedResponseList = legacyBatchEvents(successRespList);
batchedResponseList = legacyBatchEvents(dontBatchFalseOrUndefinedResponses);
}
}
return [...batchedResponseList, ...errorRespList];
return [
...batchedResponseList,
...errorRespList,
// if there are any events where dontbatch set to true we need to update them according to the response format
...convertToResponseFormat(dontBatchTrueResponses),
];
};

module.exports = { process, processRouterDest };
32 changes: 32 additions & 0 deletions src/v0/destinations/hs/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const {
getValueFromMessage,
isNull,
validateEventName,
defaultBatchRequestConfig,
defaultPostRequestConfig,
getSuccessRespEvents,
} = require('../../util');
const {
CONTACT_PROPERTY_MAP_ENDPOINT,
Expand Down Expand Up @@ -837,6 +840,34 @@ const addExternalIdToHSTraits = (message) => {
set(getFieldValueFromMessage(message, 'traits'), externalIdObj.identifierType, externalIdObj.id);
};

const convertToResponseFormat = (successRespListWithDontBatchTrue) => {
const response = [];
if (Array.isArray(successRespListWithDontBatchTrue)) {
successRespListWithDontBatchTrue.forEach((event) => {
const { message, metadata, destination } = event;
const endpoint = get(message, 'endpoint');

const batchedResponse = defaultBatchRequestConfig();
batchedResponse.batchedRequest.headers = message.headers;
batchedResponse.batchedRequest.endpoint = endpoint;
batchedResponse.batchedRequest.body = message.body;
batchedResponse.batchedRequest.params = message.params;
batchedResponse.batchedRequest.method = defaultPostRequestConfig.requestMethod;
batchedResponse.metadata = [metadata];
batchedResponse.destination = destination;

response.push(
getSuccessRespEvents(
batchedResponse.batchedRequest,
batchedResponse.metadata,
batchedResponse.destination,
),
);
});
}
return response;
};

module.exports = {
validateDestinationConfig,
addExternalIdToHSTraits,
Expand All @@ -856,4 +887,5 @@ module.exports = {
getObjectAndIdentifierType,
extractIDsForSearchAPI,
getRequestData,
convertToResponseFormat,
};
94 changes: 94 additions & 0 deletions src/v1/destinations/hs/networkHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* eslint-disable no-param-reassign */
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
/* eslint-disable no-restricted-syntax */
const { TransformerProxyError } = require('../../../v0/util/errorTypes');
const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network');
const { isHttpStatusSuccess, getAuthErrCategoryFromStCode } = require('../../../v0/util/index');

const {
processAxiosResponse,
getDynamicErrorType,
} = require('../../../adapters/utils/networkUtils');
const tags = require('../../../v0/util/tags');

const verify = (results, rudderJobMetadata) =>
Array.isArray(results) && results.length === rudderJobMetadata.length;

const populateResponseWithDontBatch = (rudderJobMetadata, status, response) => {
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
const errorMessage = JSON.stringify(response);
const responseWithIndividualEvents = [];
for (const metadata of rudderJobMetadata) {
metadata.dontBatch = true;
responseWithIndividualEvents.push({
statusCode: 500,
metadata,
error: errorMessage,
});
}
return responseWithIndividualEvents;
};
const responseHandler = (responseParams) => {
const { destinationResponse, rudderJobMetadata } = responseParams;
const successMessage = `[HUBSPOT Response V1 Handler] - Request Processed Successfully`;
const failureMessage =
'HUBSPOT: Error in transformer proxy v1 during HUBSPOT response transformation';
const responseWithIndividualEvents = [];
const { response, status } = destinationResponse;

if (isHttpStatusSuccess(status)) {
// populate different response for each event
const results = response?.results;
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
if (verify(results, rudderJobMetadata)) {
for (const [idx] of rudderJobMetadata.entries()) {
const proxyOutputObj = {
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
statusCode: 200,
metadata: rudderJobMetadata[idx],
error: 'success',
};
responseWithIndividualEvents.push(proxyOutputObj);
}
return {
status,
message: successMessage,
destinationResponse,
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
response: responseWithIndividualEvents,
};
}
// return the destiantionResponse as it is when the response is not in expected format
return {
status,
message: successMessage,
destinationResponse,
response: destinationResponse,
};
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
}

// At least one event in the batch is invalid.
if (status === 400 && rudderJobMetadata.length > 1) {
// sending back 500 for retry only when events came in a batch
return {
status: 500,
message: failureMessage,
destinationResponse,
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
response: populateResponseWithDontBatch(rudderJobMetadata, status, response),
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
};
}
throw new TransformerProxyError(
failureMessage,
status,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
destinationResponse,
getAuthErrCategoryFromStCode(status),
responseWithIndividualEvents,
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
ItsSudip marked this conversation as resolved.
Show resolved Hide resolved
);
};

function networkHandler() {
this.prepareProxy = prepareProxyRequest;
this.proxy = proxyRequest;
this.processAxiosResponse = processAxiosResponse;
this.responseHandler = responseHandler;
}

module.exports = { networkHandler };
Loading
Loading