This article is relevant if you are working with NetSuite with scheduled or map/reduce scripts and you seek to gain control over multiple executions.
Background
In our NetSuite Systems Integration Practice, we write many scheduled scripts. More and more, we use the Map/Reduce pattern to work NetSuite business records. In these types of NetSuite programs, there are times that we want our logic to be fired on-demand, or on the back of saving business records (via UserEvents) while we also want our logic to run in a scheduled manner.
An approach we use to achieve this objective is to create two deployments of the script:
- Scheduled: this deployment is set up to run at a regular frequency and controlled during configuration.
- Unscheduled: this deployment is set so that we can call the script on-demand or on the back of UserEvents.
There are situations where you don’t want the script running at the same time. The idea is that there is a set of work to do and you don’t want a script running simultaneously on the same set of work. In these cases, you need a strategy to address the situation.
Detect if a NetSuite Scheduled Script is Already Running
I want to thank Boban D., a senior member on our team for bringing this concern forth and offering the following SuiteScript 2.0 function. This JavaScript can be used to have your Scheduled script detect if it is already running in another deployment. If so, then you have an opportunity to stop processing business logic on the newly created instance that is now running in parallel with the already running script.
function anotherDeploymentIsExecuting() { var ss = search.create({ type: record.Type.SCHEDULED_SCRIPT_INSTANCE, filters: [ ["status","anyof","PENDING","PROCESSING","RESTART","RETRY"] ,"AND", ["script.scriptid",search.Operator.IS,runtime.getCurrentScript().id] ,"AND", ["scriptDeployment.scriptid",search.Operator.ISNOT,runtime.getCurrentScript().deploymentId] ], columns: ["status", "script.internalid"] }).run().getRange(0,1); return (ss.length > 0); }
Work with NetSuite Technology Experts
Our NetSuite Systems Integration Practice allows us to see so many client situations. Accordingly, our expertise deepens to drive the NetSuite platform to solve our clients’ concerns.
If you found this article helpful, feel free to sign up to receive notifications of new articles as I post them. If you would like to be appreciated for your talent and leadership in the NetSuite domain, let’s have a conversation.
HI Marty,
Thought i’d share a solution i came up with.
Had a scenario that require M/R to handle some billing, that needed any user to be able trigger at anytime…
Few steps…
First the suitelet creates a “queue” record with some basic info. ie. SO numbers, email addresses etc… stored in a JSON string in a Long Text field
Second… first M/R triggers after step one, and this M/R actually builds the process queue based on the JSON string/array in step one. A “process record” for each transaction being processed. This allows dupe check/remove handling here.
Here’s the important bit.. in the Summary phase on step 2, run another search to see if any extra “queue” JSON records have been created (ie. simultaneous users triggering stuff).
If any more found, in the summary phase, trigger the same M/R to repeat again. THIS IS ALLOWED AND WORKS BEAUTIFULLY.
When no more “queue” JSON data is found, then the summary phase can trigger the ACTUAL processing M/R script to do the work based on a search of “process queues”
Same thing in summary phase, check if there are any new “process” records, and trigger the M/R again, if not… it ends.
This creates a looping solution which allows the queue to be “topped” up mid process, and in turn allows unlimited processing within a single thread.
Hello Stefan,
Thanks for that pattern and the use of the Summarize step to check a queue. Helpful!
Marty
Keep up the great work!
Here’s a similar function that uses half the governance by calling runPaged() and can handle any arbitrary script instead of only the current one.
function isExecuting(scriptId, deploymentId) {
const executingStatuses = ["PENDING","PROCESSING","RESTART","RETRY"];
return Boolean(search.create({
type: record.Type.SCHEDULED_SCRIPT_INSTANCE,
filters: [
["status", search.Operator.ANYOF, executingStatuses], "AND",
["script.scriptid", search.Operator.IS, scriptId] ,"AND",
["scriptDeployment.scriptid", search.Operator.ISNOT, deploymentId]
],
columns: ["script.internalid"]
}).runPaged().count);
}
Hi Eric,
I like it! Condensed and clean.
Marty