light-mode-image
<< Back

Using a Delay Function in NetSuite to Avoid the “Record Has Been Changed” Error in Map/Reduce Scripts

Posted by Christo Johns on 12/1/2024

Category : NetSuite ERP

When working with Map/Reduce (MR) scripts in NetSuite, one common challenge is handling the “Record has been changed” error. This error occurs when multiple processes or users attempt to update the same record simultaneously, leading to conflicts. To address this, you can implement a delay function that pauses execution, checks the elapsed time, and retries the operation. This strategy minimizes conflicts and ensures smoother script execution.

Understanding the “Record Has Been Changed” Error

This error typically arises in scenarios where:

  1. Concurrent Updates: Multiple scripts or users try to edit the same record at the same time.
  2. System Latency: Operations like record loading or submission are delayed, causing outdated data to be used during updates.
  3. High Volume Operations: MR scripts processing large datasets may encounter overlapping transactions on frequently accessed records.

The solution involves introducing a retry mechanism with a delay, allowing the system to process other transactions before retrying.

Why Use a Delay Function?

A delay function ensures the script doesn’t immediately retry an operation when the error occurs. Instead, it:

  1. Provides a Buffer: Allows other transactions to complete, reducing conflicts.
  2. Avoids Excessive Retries: By spacing out retries, it reduces the risk of repetitive errors.
  3. Improves Script Performance: Avoids abrupt script termination by managing errors gracefully.

Implementing a Delay Function in NetSuite

Here’s how to create a delay function that checks the elapsed time and retries operations:

  1. Define the Delay Function
  2. Use JavaScript’s Date object to track time and introduce pauses.
  3. Integrate with MR Script
  4. Apply the delay function in the Map or Reduce stages when the error is encountered.
  5. Handle Errors Gracefully
  6. Use a try-catch block to capture the “Record has been changed” error and invoke the delay function before retrying.

Sample Delay Function

/**
 * Function to introduce a delay by checking elapsed time
 * @param {number} milliseconds - The desired delay in milliseconds
 */
function delay(milliseconds) {
    var startTime = new Date().getTime();
    while (new Date().getTime() - startTime < milliseconds) {
        // Wait until the specified time has elapsed
    }
}

Example Usage in an MR Script

/**
 * @NApiVersion 2.x
 * @NScriptType MapReduceScript
 */
define(['N/record', 'N/log'], function(record, log) {
    function map(context) {
        var recordId = context.value;
        var maxRetries = 5; // Maximum retry attempts
        var retryCount = 0;
        var delayTime = 2000; // 2 seconds delay

        while (retryCount < maxRetries) {
            try {
                // Load and update the record
                var rec = record.load({
                    type: 'customrecord_example',
                    id: recordId,
                    isDynamic: true
                });

                rec.setValue({
                    fieldId: 'custrecord_status',
                    value: 'Processed'
                });

                rec.save();
                log.debug('Record Updated Successfully', recordId);

                // Break out of the loop if successful
                break;
            } catch (e) {
                if (e.name === 'RECORD_CHANGED') {
                    retryCount++;
                    log.debug('Retry Attempt', retryCount);

                    // Introduce a delay before retrying
                    delay(delayTime);

                    if (retryCount === maxRetries) {
                        log.error('Max Retries Reached', `Record ID: ${recordId}`);
                        throw e;
                    }
                } else {
                    // Log and throw non-related errors
                    log.error('Unexpected Error', e);
                    throw e;
                }
            }
        }
    }

    return {
        map: map
    };
});

Key Considerations

  1. Limit Retry Attempts
  2. Set a maximum number of retries to avoid infinite loops and excessive script execution time.
  3. Balance Delay Duration
  4. Adjust the delay time based on the system’s transaction volume. A delay of 2–5 seconds is usually sufficient.
  5. Monitor Script Performance
  6. Track script logs to analyze the frequency of retries and adjust delay logic as needed.
  7. Use Efficient Record Handling
  8. Minimize the chances of conflicts by optimizing the script to process records in batches or during low-traffic periods.

Advantages of Using a Delay Function

  1. Enhanced Reliability: Reduces the likelihood of script failures due to record conflicts.
  2. Improved Scalability: Allows scripts to handle large datasets without frequent interruptions.
  3. Better Resource Management: Avoids overloading the system with repeated immediate retries.

Conclusion

The “Record has been changed” error is a common hurdle in NetSuite MR scripts, but it can be effectively managed with a delay function. By incorporating a retry mechanism with controlled delays, you ensure your scripts run reliably, even in high-volume or concurrent update scenarios. Implementing this solution not only minimizes conflicts but also improves overall script performance and system stability.

Tags: