How to Stop a NetSuite Map/Reduce Script Safely
Cancel a pending NetSuite Map/Reduce deployment, contain one that is already processing, assess partial work and add a cooperative stop switch.
The way to stop a NetSuite Map/Reduce script depends on its current state:
- If all its tasks are Pending, cancel the instance from the Map/Reduce Script Status page.
- If work is already Processing, cancellation is no longer a reliable instant-stop operation. Prevent another submission, contain the deployment and assume that some records may already have changed.
NetSuite’s N/task module can submit a Map/Reduce task and check its status, but it does not provide a method that cancels a running Map/Reduce task.
Find the exact script instance
Go to:
Customization → Scripting → Map/Reduce Script Status
Then:
- Set the date to today or the expected submission date.
- Set Status to Unfinished.
- Confirm the script, deployment and submission time.
- Open the instance details to identify its current stage and task statuses.
Do not stop a deployment merely because its name looks familiar. The same script can have several deployments with different schedules, parameters or subsidiaries.
Cancel a pending Map/Reduce instance
NetSuite’s Map/Reduce Script Status documentation states that a deployment can be cancelled from the status page when all tasks are pending.
If processing has not begun:
- Locate the instance on the status page.
- Click Cancel.
- Refresh the status view and confirm that it is no longer unfinished.
- Disable or correct the schedule that submitted it if another run would immediately replace it.
This is the cleanest case because the custom Map/Reduce entry points have not begun changing records.
Why the Cancel option disappears
A Map/Reduce instance is not one continuous script execution. NetSuite divides it into jobs for the input, map, shuffle, reduce and summarize stages. Map and reduce can use several jobs in parallel.
Once one or more jobs begin processing, the entire instance is no longer wholly pending. NetSuite may therefore stop offering the same Cancel action.
Changing concurrency or priority is not cancellation. Those settings affect scheduling and processor allocation; they do not undo completed work.
Contain an instance that is processing
When processing has begun, treat the situation as containment and recovery rather than a guaranteed rollback.
Prevent another submission
Open the exact script deployment and disable its schedule or make the deployment inactive, depending on how it is submitted. If several deployments use the same script, change only the affected deployment where possible.
Inactivating the parent script record is a broader emergency measure because it affects every deployment belonging to that script. Record its original state before changing it.
These changes are useful for preventing another run. Do not assume that they reverse completed changes or interrupt an entry-point invocation at an exact line of code.
Monitor the current jobs
Return to the Map/Reduce Script Status page and watch:
- Current stage
- Pending versus processing tasks
- Percentage complete
- Errors
- Start and end times
Map/Reduce yielding happens between function invocations. Oracle notes that yielding does not interrupt a function that is currently running, and SuiteScript does not provide an API that manually forces a yield.
Protect high-impact downstream actions
If the script sends email, calls an external API, creates payments or performs another high-impact action, disable the narrowest available downstream trigger if the incident requires it.
Avoid broad account changes unless they are genuinely necessary. Record every temporary change so it can be reversed afterward.
Stopping does not roll back completed work
Each map or reduce invocation may commit its own changes. Cancelling or containing the instance does not create a transaction around the entire run.
Before restarting, determine:
- Which records were selected as input.
- Which keys completed successfully.
- Which records were created or changed.
- Whether external requests were sent.
- Whether a key can be processed again safely.
- Whether summarize ran and recorded errors.
Do not immediately reactivate the deployment and press Save and Execute. A second run can duplicate completed work when the script is not idempotent.
Check status from SuiteScript
Store the task ID returned when submitting the deployment:
/**
* @NApiVersion 2.1
*/
define(['N/task'], (task) => {
const submitMapReduce = () => {
const mapReduceTask = task.create({
taskType: task.TaskType.MAP_REDUCE,
scriptId: 'customscript_example_mr',
deploymentId: 'customdeploy_example_mr',
});
return mapReduceTask.submit();
};
const getMapReduceStatus = (taskId) => {
const status = task.checkStatus({ taskId });
return {
status: status.status,
stage: status.stage,
pendingMapCount: status.getPendingMapCount(),
pendingReduceCount: status.getPendingReduceCount(),
};
};
return { submitMapReduce, getMapReduceStatus };
});
Status monitoring is useful for a Suitelet or integration dashboard, but task.checkStatus() does not grant a cancellation capability.
Add a cooperative stop switch
For important deployments, design a stop switch before it is needed. A control custom record is narrower and more explicit than inactivating the entire script.
For example, create a control record with a custrecord_stop_requested checkbox and inspect it before each unit of work:
/**
* @NApiVersion 2.1
* @NScriptType MapReduceScript
*/
define(['N/search'], (search) => {
const CONTROL_RECORD_ID = 1;
const stopRequested = () => {
const fields = search.lookupFields({
type: 'customrecord_mr_control',
id: CONTROL_RECORD_ID,
columns: ['custrecord_stop_requested'],
});
return fields.custrecord_stop_requested === true;
};
const getInputData = () => {
if (stopRequested()) {
return [];
}
return search.load({ id: 'customsearch_example_input' });
};
const map = (context) => {
if (stopRequested()) {
return;
}
// Process one key idempotently.
};
const reduce = (context) => {
if (stopRequested()) {
return;
}
// Process one unique key idempotently.
};
const summarize = (summary) => {
log.audit({
title: 'Map/Reduce summary',
details: {
stopRequested: stopRequested(),
seconds: summary.seconds,
usage: summary.usage,
yields: summary.yields,
},
});
};
return { getInputData, map, reduce, summarize };
});
This is a cooperative stop, not queue cancellation. NetSuite may continue invoking map or reduce for remaining keys, but each invocation returns without performing its business operation.
The lookup consumes governance on every invocation. For a high-volume deployment, balance polling frequency against how quickly the script must respond.
Make operations safe to repeat
Oracle recommends idempotent handling because interrupted jobs can restart. A restarted context can indicate isRestarted, but that flag does not prove that the current key already completed.
Protect the operation itself:
const map = (context) => {
const input = JSON.parse(context.value);
if (outputAlreadyExists(input.externalKey)) {
return;
}
createOutputWithExternalKey(input);
};
A durable external key, processed marker or reconciliation lookup is safer than relying only on an in-memory set or the restart flag.
If a function creates an external side effect, use an idempotency key or correlation ID before assuming a retry is harmless.
Restart safely
- Leave the deployment disabled while investigating.
- Record the incomplete instance details and errors.
- Reconcile records already processed.
- Correct the cause of the runaway or incorrect processing.
- Restrict the next input to genuinely unfinished work.
- Test with a small dataset under the production execution role.
- Clear any cooperative stop flag.
- Reactivate the deployment.
- Submit one controlled instance and monitor it through summarize.
If the input search still selects completed records, restarting the same code is not a recovery plan.
Design for interruption
Keep Buffer Size at 1
Oracle recommends leaving Buffer Size at 1 for most scripts. A larger buffer increases the number of key-value pairs flagged for a job and can increase duplication risk after interruption.
Keep each invocation small
Map and reduce should process small independent units. A function containing a long internal loop is harder to contain and cannot yield in the middle of that invocation.
Bound the input
Use an input search that can exclude completed work and be narrowed by parameters such as date, subsidiary or batch ID.
Make summarize useful
Collect input, map and reduce errors and log usage, yields and elapsed time. A useful summary makes partial-run recovery much easier.
Configure retries deliberately
retryCount and exitOnError control what happens after errors in map or reduce. They do not replace idempotency and they are not a manual cancellation interface.
Common mistakes
Assuming cancellation means no work occurred
Always inspect the instance. A processing job may already have committed changes.
Inactivating the parent script without recording why
This can affect unrelated deployments. Prefer the narrowest deployment-level change and leave an incident note.
Resubmitting immediately
Only one unfinished instance of a particular deployment can exist at a time, but a replacement run can still repeat work after the earlier instance finishes or is contained.
Looking for N/task.cancel()
N/task supports submission and status monitoring for Map/Reduce tasks. It does not expose that cancellation method.
Throwing an error as a kill switch
An uncaught error affects the current invocation and interacts with retryCount and exitOnError. It is not a predictable whole-instance cancellation mechanism.
Quick response checklist
- Identify the exact deployment and unfinished instance.
- If every task is pending, use Cancel on the status page.
- If processing has begun, prevent another submission and monitor containment.
- Protect high-impact downstream actions if necessary.
- Assume partial work exists until reconciliation proves otherwise.
- Fix the input or operation before restarting.
- Add idempotency and a cooperative stop switch for the next incident.