Friday, October 22, 2021

Maximo Automation Scripting Best Practices for Performance

Automation Scripting is a feature in Maximo used to implement business logic using any JSR 223 specification compliant Scripting language

The automation script code get compiled to Java bytecode, gets cached as part of Maximo runtime. When the script is invoked, it is cached bytecode that is executed by JVM in the same thread as other Maximo business logic written in Java. A poorly written code can cause performance issue, so we need to follow a few guidelines similar to Java customization.       

Cautious of having Multiple Scripts for Single Launch Point Event

Maximo allows to include multiple scripts for the same launch point triggering event. Maximo event topic is un-ordered map, where the events gets fired without any sequence. 
 
If you write script that need to be executed in specific order or need any pre-requisite actions on the same launch point, then it cause issues on the expected output.
 
Possible solution: Ensure that there is no dependency between scripts or combine them into a single script

Use of Single script for Multiple Launch points

We should try to create a single script where we need a generic business logic and attach it in multiple launch points. 

One such business case is to restrict description to 50 characters between Maximo and other external systems.

------------------------------------------------------------------------

strLen = len(mbo.getString("description")) ;

if(strLen > 50):

   service.error("system","DescriptionFieldLimit");

--------------------------------------------------------------------------

Above script can be attached to any MBO where description need to be restricted.

Choice of Launch point and Event

Launch points decide when the script need to be triggered. Choosing a right launch point can help avoid certain performance issue. 

Case 1: skipping an outbound integration message can be done using 2 launch points: User Exit Scripting or Publish Channel Event Filter. The best launch point to use is Event Filter because the skip action happens before the serialization of MBOs. Sample script for Event Filter to skip records based on status is below:

---------------------------------------------------------------------

If service.getMbo().getString("status")== "APPR":

evalresult = False

evalresult = True

--------------------------------------------------------------------

Case 2: Initialization of Attribute value can be set using Object Launch Point or Attribute Launch Point with Event - Initialize Value. We must use Attribute Launch Point, because Object Launch point can lead to performance issues when selecting a lot of MBOs in List tab, escalations or API actions. 

Naming Convention for Automation Script

As we know the launch points play an important role on the Scripting Performance. We need to have a way to identify the launch point of the script without navigating to the launch point tab & dialog in Scripting application.

The Name can be written in 

TABLE_SCRIPTTYPE_ATTRIBUTE_EVENT_DESCRIPTION

TABLE is WORKORDER, ASSET, PO, PR etc.,
SCRIPTTYPE can be Object, Library, Action, Attribute level, Integration and Custom Condition. 
ATTRIBUTE - Attribute name; It is used only for attribute launch point scripts 
EVENT - It's predefined triggering point. Before Save, After Save, After Commit, Attribute Initialize Value, etc.,
DESCRIPTION - can be any free text. You can ignore it based on your field length.
for example: WORKORDER_OBJECT_BEFORESAVE
WORKORDER_FLD_PRIORITY_MANDATE_INITVAL
COMMON_LIB_LIMITDESC

Avoid initialization Events from List tab

You can perform heavy initialization logic once the MBO is opened in Maximo Main tab. Doing the same action when it is loaded in List tab would cause poor response time on loading a lot of records. 

-----------------------------------------------------------------------------------------------------------------------

from psdi.common.context import UIContext

if UIContext.getCurrentContext() is not None and UIContext.isFromListTab() == False:

print ("the logic goes here")

-------------------------------------------------------------------------------------------------------------------------

Use MboSet.count() only once or isEmpty() instead

MboSet.count() calls sql script to Database every time it is executed in the script. 

In order to improve the performance, write the script once and store it in a variable. 

--------------------------------------------------------------------

cnt = mboset.count()

if cnt <= 1:

        service.log("skipping this as count is " + cnt)

-------------------------------------------------------------------

or use mboset..isEmpty() to check if the count is zero. isEmpty() will be called once if mboset is not initialized, any more calls to this function will be accessed from memory without hitting the database.

Close the MboSet opened from MXServer.getMXServer.getMboSet("")

Maximo framework will always release the mboset that are created by launch point mbo or related objects mbo.getMboSet().
 
But, for Mbosets opened using the server MXServer.getMXServer.getMboSet("") api, the programmer is responsible to close the mbosets. If it is not handled, it may lead to OutOfMemory Error. 

------------------------

try:

    xxxxxx

finally:

    mboset.cleanup()

-------------------------

Check if logging is enabled before writing log statements

As a thumb rule, write the print or log statements only after checking whether the logging is enabled or not. The file write operations would take reasonable amount of time to complete the execution of code. 

-----------------------------------------------------------------------------

from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger("maximo.script”);

debugEnabled = logger.isDebugEnabled()


if debugEnabled:

 service.log("MBOs saved in DB"+mboset.count())

-------------------------------------------------------------------------------

Avoid calling SAVE in middle of transaction

MBOs created or updated by a launch point script or by its related mboset are always part of the single transaction .i.e., committed into database by a single SAVE. 

If you create or update a MBO by MXServer.getMXServer().getMboSet("objectname"), those changes would be outside of the script execution. You need to add it by this code: 

------------------------------------------------------------------------------------------

newMboSet = MXServer.getMXServer.getMboSet("WORKORDER")

mbo.getMXTransaction.add(newMboSet)

------------------------------------------------------------------------------------------

In real time scenario, the chances of using this code is very rare and tricky too. 

Reference: Scripting_Best_Practices_For_Performance.pdf

service-methods-automation-scripts.html 

No comments:

Post a Comment