This article is relevant if you are a NetSuite SuireScript developer and you are concerned about running out of script deployments for your scheduled or map/reduce scripts.
Background
In our professional services practice, we created a tool called “Queue Manager” to help us with complex NetSuite jobs. The Queue Manager simply is a record structure to help us understand when we want to schedule or queue up background processing work — using it helps us optimize the way we use threads/processors in our many client environments.
Using the Queue Manager requires the developer to either create a scheduled or map/reduce script to fire the specific logic against data that is in the queue. Some of our technical developers had a particular understanding about NetSuite script deployments that was incorrect — and thus we were overburdening ourselves with managing how we interacted with script deployment IDs.
The Misunderstanding About SuiteScript Deployments
Working with one of our Senior Analysts, Boban D. when you want to “kick off” either a scheduled script or a map/reduce script, from within another script, you use the task.create() function. Here you have two choices:
- Specific ID: choose to specify a deployment ID, or;
- No ID: omit the deployment ID, in which case NetSuite will select one of the available deployments.
When you fire a script without specifying the ID, if there are no deployments available because it is busy processing, then NetSuite will raise an error. Thus the concern is that we don’t want to run out of deployments and thus bring forth errors. For this reason, when we created Scheduled Scripts which were processing Queue Manager records (just a list of work to do), we generally recommended that the script had three deployments:
- Deployment 1: Scheduled, to run every XX minutes
- Deployment 2: Unscheduled to kick off immediate jobs
- Deployment 3: Unscheduled to kick off more work or to address jobs that require rescheduling
The idea was that a script would add something to the Queue — and we would want to immediately kick off one of the above “processing scripts” (deployments 2 or 3) to do the real work; this would cause one of the Unscheduled deployments to execute (let’s say Deployment 2). This processing script would run, and potentially process many Queue Manager records (maybe thousands were written to the queue). When Deployment 2 ran out of capacity, just before exiting, it would use task.create() to execute another instance of itself. And since Deployment 2 was running, NetSuite would now start deployment 3. If deployment 3 also eventually ran out of capacity, it would do the same, and it would kick off deployment 2 again, and the hope was that these two deployments went back-and-forth making script deployments available to the environment.
We (thought) we had to do it this way because you can’t successfully use task.create() to run a script unless one of the deployments was available. We had a similar problem if at the end of a Map/Reduce script, we wanted to re-execute that same Map/Reduce script.
The Correct Deployment Usage Pattern
However, Boban D. learned from another one of our Senior Analysts, Sean G., that when you use task.create() (or the SuiteScript 1.0 equivalent) to start a scheduled or map/reduce script, if you give it the SAME deployment ID which is currently running (in other words, Deployment 2 requests to task.create() Deployment 2 AGAIN in the example above), then NetSuite will NOT raise an error. It will simply put that same script into NetSuite’s script queue, and as soon as the current execution finishes, NetSuite will re-run it.
So for the scenario above, you need only a single unscheduled deployment, and if it runs out of governance, it schedules itself again. Thus, you specifically reference the Deployment ID of the unscheduled script and it will build up a NetSuite queue of scheduled work to do automatically.
Work with a Senior NetSuite Technology Team
I thought this article would be helpful to the NetSuite technical community. While many technical people are very intelligent, it shows how we can be blinded by our ignorance or misunderstandings. Thus, we believe, as a Systems Integration Practice, it is valuable to talk about our learnings to make ourselves better NetSuite professionals. We have invested much to see NetSuite succeed in our client organizations. Let’s help all of us reinforce success on the platform.
If you found this article relevant, feel free to sign up for notifications to new articles as I post them. If you are ready to tackle your shipping revenue, shipping margin challenges, let’s have a conversation.
Hi Marty
This sounds very similar to a solution I shared with you back in September last year:
https://blog.prolecto.com/2020/09/20/solve-for-simultaneous-netsuite-scheduled-or-map-reduce-script-deployments/#comment-11023
Using your queue scenario, the easiest method was to check the queue list in the Summary stage of the Map/Reduce and if any remaining queued tasks exist unprocessed, the summary stage can restart the same deployment.
Thank you Stefan,
Indeed, that is a good use of the Map/Reduce Summary stage.
Marty
If I understand the secondary solution, The concept of having just one deployment record for a scheduled task and calling that multiple times and expecting NetSuite to auto handle the queueing of it doesn’t seem to work. I had one deployment for a sched task. I have a logic where mult. instances of a scheduled script could be called as a user clicks a button. I call it with var scriptTask = task.create({
taskType: task.TaskType.SCHEDULED_SCRIPT,
scriptId: “customscript_scheduledautopack”,
deploymentId: “customdeploytest”,
params: {
‘custscript_scheduledif’: fulfillmentID,
‘custscripttc_schedautopackmode’: mode
} and when I try to call that back to back from diff transactoins, I get an error FAILED_TO_SUBMIT_JOB_REQUEST_1″,”details”:”Failed to submit job request: INPROGRESS. So it would seem to me that it is not queueing on the 2nd,3rd, etc. request for the sched. task creation.
Hello John,
I wonder if you are using different params values for fulfillment ID and thus it sees it as something separate? Did you try this pattern without the params values?
Marty