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 };
});