Chidi Okwudire IT Professional. ERP Enthusiast. NetSuite Certified (Administrator, SuiteCloud Developer II, and ERP Consultant). Celigo Certified (Level 4+). Passionate About Empowerment Through Knowledge Sharing. Always Eager to Learn.

How To Easily Understand The Dispatcher Script Pattern

7 min read

What is the dispatcher script pattern? Larry at Asoville Inc. is puzzled. The client script he recently deployed to Production is not firing and he simply cannot figure out why! He has ruled out the common culprits, like the script being in an unreleased state or not exposed to the necessary user roles but there’s no smoking gun. He finally reaches out to NetSuite Support; they point out that he has too many client scripts deployed to the record and NetSuite will only execute the first 10. What?! Larry has heard about a general recommendation of at most 10 script active deployments per record type but he never realized that it is enforced for client scripts.

Anyway, identifying the cause of the problem is helpful, but how can he solve the issue? His script is currently the 12th on the list. While he can move his script into the top 10, it means another script will stop running, and he cannot quickly assess the impact. Moreover, some of these scripts were developed way before he joined the company and he does not quite know what they do. To make matters worse, he is under time pressure as the finance team needs to close the books urgently. Thus, studying the scripts and refactoring them, while a good idea in the long term, is not quite an option either. In desperation, he reaches out to NS support again asking if they can raise the client script limit (even temporarily) in their account from 10 to 12. The answer is a predictable “No” (Who does this Larry think he is anyway?!). Larry is not sure where to go from here.


Hopefully, you’re not reading this article because you are in a situation like Larry’s (but if you are, we’ve got you covered). In this article, you will learn what the dispatcher script pattern is and how you can leverage it to prevent situations like Larry’s in the first place and/or to quickly and effectively “combine” (un)related scripts without refactoring them.

The Dispatcher Script Pattern

Dispatcher script pattern - architecture

The above diagram summarizes the pattern. Instead of deploying multiple scripts to a record, we replace them with a single “dispatcher”. This allows us to meet NetSuite’s script deployment constraints and may have a positive impact on performance.

While the concept is very simple, I understand that the above diagram might be a bit too abstract, so we will work through a simplified scenario to unpack the pattern.

But first, let’s make sure we understand the problem.

NetSuite’s Script Deployment Constraints

Scripting is one of NetSuite’s major offerings for extending the platform with additional functionality. NetSuite scripts fall into two categories: those that run on the user’s browser (client scripts) and those that run on the NetSuite server (server scripts). An exhaustive coverage of NetSuite’s script types is beyond the scope of the current discussion. What is relevant is that the client script and the user event script types can be deployed to records. Thus, one or more scripts of these types can be deployed to one or more record types (it is a many-to-many relationship).

When I first started working with NetSuite, the user event script type was confusing to me. Because of the word “user” in the script type name, I was inclined to think that it executes in the user’s browser (i.e. client side). That is incorrect – user event scripts are one of the many server script types. A better way to think of it is that user event scripts execute on the server in response to actions initiated by a user e.g. viewing, creating, copying, editing, or deleting a record.

Via menu Customization > Scripting > Scripted Records, you can access information about scripts, workflows, and other customizations applied to each record type.

Path to Scripted Records page

When you select a record type from the Scripted Records page and open it in edit mode, you will see the following message at the top of the subtab for client scripts:

“You can specify the order in which global client scripts are executed for this scripted record. However, for performance reasons, only the first 10 deployed scripts will be executed.”

NetSuite SCripted REcord page

That is as clear as it gets. A hard limit of 10 client scripts per record type. Interestingly, the constraint for user event scripts is softer. It is merely a recommendation: “You can specify the order in which user event scripts are executed for this scripted record. Note that deploying too many user event scripts of the same trigger type may impact performance. NetSuite recommends deploying no more than 10 scripts of the same trigger type, however, all scripts set to Deployed will execute.”

While it is unclear what is special about the number 10 and why NetSuite enforces this for client scripts and not for user event scripts, it is generally true that the more scripts deployed to a record, the higher the likelihood of performance issues. We will explore performance in a separate article. For now, though, the takeaway is that there is a hard limit for client scripts that we need to respect.

Client Script Limitation Illustrated

To illustrate the issue, consider a test custom record type to which I have deployed 12 placeholder scripts.

Custom record with 12 deployed client scripts
Custom record with more than 10 deployed client scripts

All each of these client scripts does is print a line to the console upon loading the record. It cannot get any simpler.

/**
 * @NApiVersion 2.1
 * @NScriptType ClientScript
 * @NModuleScope SameAccount
 */
define([],
function() {

    const TAG = 'PLACEHOLDER 1';
    /**
     * Function to be executed after page is initialized.
     *
     * @param {Object} scriptContext
     * @param {Record} scriptContext.currentRecord - Current form record
     * @param {string} scriptContext.mode - The mode in which the record is being accessed (create, copy, or edit)
     *
     * @since 2015.2
     */
    function pageInit(scriptContext) {
        console.log(`I am ${TAG}`);
    }

    return {
        pageInit
    };
    
});

Here’s the console output Indeed, viewing a record of this type. Indeed placeholder scripts 11 and 12 do not execute!

Only the first 10 client scripts are executed

Applying The Dispatcher Script Pattern

Migrating to the dispatcher script pattern is very straightforward. I suspect ChatGPT will be able to execute these steps with the right request.

Sample dispatcher script implementation

Step 1: Create the Dispatcher Script

Create the dispatcher client script and name it whatever you like. I like to include the word “Dispatcher” in the name to indicate its purpose. I’ve seen names that use the word “EntryPoint” to the same end.

Step 2: Add Each Script to be Replaced as a Dependency

In the define section of your script, include a reference to JavaScript files linked to each of the scripts that you want to replace. In our case, that will be placeholders 1 – 12.

Step 3: Implement the Entry Points

In the dispatcher script, implement each entry point that is used by one or more of the scripts being replaced. The Scripted Records page is helpful to this end as it gives an overview of implemented entry points per script. In our example, all the scripts implement just the pageInit() entry point. Thus, that is the only one we care about.

As illustrated in the code block above, all the dispatcher script does is invoke the corresponding entry point function in the replaced scripts.

While scripts are generally independent, the order in which they execute might affect the results. Thus, when implementing the dispatcher script, be sure to call the dependencies in the same order as they deployed to the record. In our example, we need to call placeholders 1 – 12 in that order.


The Results

Here is the scripted record page after deploying the dispatcher script. Note that although the original scripts are still visible on the page, they will not fire directly as they are undeployed. Instead, they will be invoked via the dispatcher script.

Scripted record after migrating to dispatcher script pattern
Scripted Record after migrating to the Dispatcher Script Pattern

Thus, from NetSuite’s perspective, we have gone from 12 scripts in our example to one. Additionally, all 12 scripts are executed as evidenced by the console logs.

With the dispatcher pattern implemented, all 12 client scripts now execute

Considerations

What I like most about the dispatcher pattern is how easy and fast it is to refactor existing scripts to use this pattern. Without having to worry about what each script is doing, we can safely refactor it and become compliant with NetSuite’s script deployment constraints. I have also found it to be a useful approach for avoiding collision when multiple developers are working on the same record type. That said, there are a few important considerations.

Source Code is Less Accessible

It is very common for developers and technical analysts to quickly view or edit code via the script file attached to the script record.

With the dispatcher script pattern in place, you will need to find the actual script in the file cabinet as the dispatcher only has “forwarder” logic.

Accessing script file via script record

Logs Might Become Harder to Isolate

Similar to the above, logging from all the dispatched scripts will now be visible under the single dispatcher script. If those logs do not include proper contextual information, it might be hard to determine which log came from which actual script. As logging is a key way for debugging in NetSuite, this issue might be very impactful. The solution is to implement proper contextual logging where the title of each log line includes the script and function from where it was produced. This is a recommended practice even when not using the dispatcher pattern.

Incorrect Order of Execution Might Change Behavior

If the order of dispatch function calls is changed, the logic might be affected if there are dependencies between the scripts. Similarly, reordering the scripts via the Scripted Records page is no longer possible.

The Dispatcher Pattern May Not Be Feasible

Our example considered scripts developed within the NetSuite account. How about scripts that are coming from third-party bundles? Can they be refactored within your account to use the dispatcher pattern? The answer is: It depends. NetSuite has a concept of script module scope which can be used to limit access to bundled scripts. See NetSuite’s help article “Controlling Access to Scripts and Custom Modules“. If the script in question has a restrictive scope, you may not be able to import it into the dispatcher script.

Note that even if it is possible to migrate scripts from third-party bundles to the dispatcher pattern, the more pertinent question is: Should you? Hopefully, you do not have 10+ bundles deployed to any of your records. But if you do, this might be your recourse.

Implementing the Dispatcher Pattern Might Hide the Real Performance Issues

If you have 10+ client or user scripts executing on a given record, chances are that there are inefficiencies and logic that can be combined to produce a more performant implementation. Using the dispatcher pattern to combine unrelated scripts should be considered a stopgap solution to buy time to work on proper refactoring. If you are facing performance issues, do not mask symptoms with clever patterns; instead, take the plunge to uncover and address the root cause.


The Verdict

The dispatcher script pattern is a fast and safe way to comply with NetSuite’s script deployment constraints. As a NetSuite developer (whether working in a single account or producing a bundle to be deployed to multiple accounts), it is highly recommended to avoid many script deployments per record type due to performance considerations. As a NetSuite administrator or business analyst, watch out for solutions and bundles in your account that do not adhere to this pattern as they might be the source of your future headaches.

Avoid deploying more than one user event script or client script to any record type whenever reasonable to avoid performance penalties

I find this pattern very useful and lean more and more toward it in my NetSuite development. My experience is that it is better to set it up from the onset rather than refactoring later. While this article has covered the dispatcher pattern for client scripts, the same principle applies to user event scripts. There are variants of this pattern e.g. creating a single Transaction dispatcher user event script that implements a case statement to trigger appropriate business logic on various transaction types to which the script is deployed.

Check out Part 2 of this series where I explore to what extent the dispatcher pattern, by itself, offers performance benefits.

NetSuite Insights is on a mission to raise the standards around NetSuite practices, one insight at a time. If that resonates with you, learn how you can become an author/collaborator here.

Don’t miss a beat – subscribe to our no-nonsense email list to have these game-changing insights hit your inbox as soon as they’re published. Ignorance? Nah, you’ve got a smarter option. Choose wisdom, choose insights!

Other Article You Might Find Interesting

Chidi Okwudire IT Professional. ERP Enthusiast. NetSuite Certified (Administrator, SuiteCloud Developer II, and ERP Consultant). Celigo Certified (Level 4+). Passionate About Empowerment Through Knowledge Sharing. Always Eager to Learn.

One Reply to “How To Easily Understand The Dispatcher Script Pattern”

  1. Very interesting article. We’ve utilized a similar pattern for Client scripts for a while now, but we generally avoid it for User Event scripts due to the way this pattern hides away what scripts are running (in addition to some of the considerations you mention). You lose the native controls given you on script deployments like deploying to only certain roles, and when an admin is trying to figure out what is going on, means a list of all scripts deployed isn’t in the Scripted Records page. I’d be interested to know what the actual performance implications are for running multiple scripts as opposed to just one, and I’d guess only a few people at NetSuite could really answer that accurately. Generally, I assume that when attempting to speed things up, there are inefficiencies in the way a script runs searches or loads and saves records that can be fixed that improve things much more than consolidating scripts or workflows. I say that without having any data though :).

Leave a Reply

×