adyen-commercetools icon indicating copy to clipboard operation
adyen-commercetools copied to clipboard

Issue with while (true) loop inside notification.handler.js

Open joakimmillen opened this issue 10 months ago • 2 comments

There is a while loop in notification.handler.js that behaves a bit unpredictable in different environments. I can't reproduce the issue locally but in our production environment it occurs at every call to the function.

https://github.com/Adyen/adyen-commercetools/blob/97bee4eaee73f7e6cc7cf8c70b32eae9e5a3eaee/notification/src/handler/notification/notification.handler.js#L88

Issue description

The while loop does not actually wait for the await statement inside the try block, leading to potentially huge amount of logs. We have this running in azure functions and one of invocations of this function had around 30 thousand logs of Update payment with key..... Running the function locally does not produce the issue but when i deploy a fix to our staging environment it seems to fix the excess logging.

Solution proposal

Instead of a while (true) {} loop just wrap everything in a recursive function that you call in the catch block if maxRetry isn't reached yet. Something like this:

async function updatePaymentWithRepeater(
  payment,
  notification,
  ctpClient,
  logger,
) {
  const maxRetry = 20
  let currentPayment = payment
  let currentVersion = payment.version
  let retryCount = 0
  let retryMessage
  let updateActions
  const repeater = async () => {
    updateActions = await calculateUpdateActionsForPayment(
      currentPayment,
      notification,
      logger,
    )
    if (updateActions.length === 0) {
      return;
    }
    logger.debug(
      `Update payment with key ${
        currentPayment.key
      } with update actions [${JSON.stringify(updateActions)}]`,
    )
    try {
      /* eslint-disable-next-line no-await-in-loop */
      await ctpClient.update(
        ctpClient.builder.payments,
        currentPayment.id,
        currentVersion,
        updateActions,
      )
      logger.debug(
        `Payment with key ${currentPayment.key} was successfully updated`,
      )
      return;
    } catch (err) {
      const moduleConfig = config.getModuleConfig()
      let updateActionsToLog = updateActions
      if (moduleConfig.removeSensitiveData)
        updateActionsToLog =
          _obfuscateNotificationInfoFromActionFields(updateActions)

      if (err.statusCode !== 409) {
        const errMsg =
          `Unexpected error on payment update with ID: ${currentPayment.id}.` +
          `Failed actions: ${JSON.stringify(updateActionsToLog)}`
        throw new VError(err, errMsg)
      }

      retryCount += 1
      if (retryCount > maxRetry) {
        retryMessage =
          'Got a concurrent modification error' +
          ` when updating payment with id "${currentPayment.id}".` +
          ` Version tried "${currentVersion}",` +
          ` currentVersion: "${err.body.errors[0].currentVersion}".`
        throw new VError(
          err,
          `${retryMessage} Won't retry again` +
            ` because of a reached limit ${maxRetry}` +
            ` max retries. Failed actions: ${JSON.stringify(
              updateActionsToLog,
            )}`,
        )
      } else (
				repeater()
			)
      /* eslint-disable-next-line no-await-in-loop */
      const response = await ctpClient.fetchById(
        ctpClient.builder.payments,
        currentPayment.id,
      )
      currentPayment = response.body // eslint-disable-line prefer-destructuring
      currentVersion = currentPayment.version
    }
  }
  return repeater()
}

joakimmillen avatar Apr 17 '24 09:04 joakimmillen

Hey @joakimmillen,

We have validated your request and it is correct. We have used the code you have provided, slightly refactored it, and tested it. It is working correctly. This will be included in the next release.

Best regards.

logeecom avatar Apr 26 '24 11:04 logeecom

Hello @joakimmillen,

Note that we’ve released a new version of the integration.

Kind regards.

logeecom avatar May 08 '24 14:05 logeecom