Yielding In suiteScript

In SuiteScript 2.x, yielding is primarily associated with Map/Reduce Scripts and, to a lesser extent, Scheduled Scripts for managing governance limits and processing large datasets efficiently. Below is a focused explanation of yielding in SuiteScript 2.x, including how it works and how to implement it.

Yielding in Map/Reduce Scripts

  • Purpose: Map/Reduce Scripts automatically yield to prevent resource monopolization and handle large datasets by pausing and resuming execution when soft limits are exceeded.
  • Soft Limits:
  • Usage Units: Each map or reduce job has a 10,000-unit governance limit. If exceeded, the system pauses the job after the current function completes and creates a new job to continue.
  • Time: The Yield After Minutes field (default 60 minutes, configurable 3–60 minutes in the script deployment) triggers yielding if a job runs too long.
  • Behavior:
  • Yielding occurs automatically without explicit coding.
  • The getInputData stage is not rerun after yielding; the system persists the initial dataset and processes only unprocessed records in subsequent jobs.
  • New jobs are created with the same priority but a later timestamp, ensuring seamless continuation.

Sample:

define([‘N/runtime’, ‘N/search’], function(runtime, search) {

  /**

   * @NApiVersion 2.x

   * @NScriptType MapReduceScript

   */

  function getInputData() {

    // Return a search or array of data to process

    return search.create({

      type: ‘transaction’,

      filters: [[‘mainline’, ‘is’, ‘T’]],

      columns: [‘internalid’]

    });

  }

  function map(context) {

    // Process each record

    var data = JSON.parse(context.value);

    var recordId = data.id;

    // Perform operations on recordId

    log.debug(‘Processing Record’, recordId);

    // Governance check (optional, as yielding is automatic)

    if (runtime.getCurrentScript().getRemainingUsage() < 1000) {

      log.debug(‘Low governance, system will yield automatically’);

    }

    context.write({ key: recordId, value: ‘processed’ });

  }

  function reduce(context) {

    // Aggregate results if needed

    var key = context.key;

    log.debug(‘Reducing Key’, key);

  }

  function summarize(summary) {

    log.debug(‘Summary’, ‘Script completed’);

  }

  return {

    getInputData: getInputData,

    map: map,

    reduce: reduce,

    summarize: summarize

  };

});

  • Key Points:
  • The system handles yielding transparently during map and reduce stages.
  • Use runtime.getCurrentScript().getRemainingUsage() to monitor governance if you want to log or take preemptive actions.
  • Configure Yield After Minutes in the script deployment to balance performance and resource usage.

Yielding in Scheduled Scripts

  • Purpose: SuiteScript 2.x does not have a direct equivalent to SuiteScript 1.0’s nlapiYieldScript. Instead, you achieve similar functionality by rescheduling the script using the N/task module when governance or time limits are approached.
  • Approach:
  • Monitor governance with runtime.getCurrentScript().getRemainingUsage().
  • Save the script’s state (e.g., current index or processed records) in a custom record, script parameter, or global variable.
  • Reschedule the script using task.create and task.submit.

Sample:

define([‘N/runtime’, ‘N/task’, ‘N/record’], function(runtime, task, record) {

  /**

   * @NApiVersion 2.x

   * @NScriptType ScheduledScript

   */

  function execute(context) {

    var script = runtime.getCurrentScript();

    var startIndex = parseInt(script.getParameter({ name: ‘custscript_start_index’ })) || 0;

    var transactions = getTransactions(); // Assume this returns an array

    for (var i = startIndex; i < transactions.length; i++) {

      if (script.getRemainingUsage() < 1000) {

        // Save state and reschedule

        var taskObj = task.create({

          taskType: task.TaskType.SCHEDULED_SCRIPT,

          scriptId: script.id,

          deploymentId: script.deploymentId,

          params: { custscript_start_index: i }

        });

        taskObj.submit();

        log.debug(‘Rescheduling’, ‘Script rescheduled at index: ‘ + i);

        return;

      }

      // Process transaction

      log.debug(‘Processing Transaction’, transactions[i]);

    }

  }

  function getTransactions() {

    // Replace with actual data retrieval logic

    return [‘tran1’, ‘tran2’, ‘tran3’, ‘tran4’];

  }

  return { execute: execute };

});

Leave a comment

Your email address will not be published. Required fields are marked *