Monday, October 8, 2018

How to handle script rescheduling with nested for loops.

Question: User has a Scheduled script that has nested for loops that is reaching the Usage Limit.

Answer:

Below is a sample script structure that will show how to do rescheduling if User has nested for loops.

1 function main()
2 {
3         
4     var logger = new Logger();
5     logger.enableDebug();
6     logger.debug('Entry Log', 'Entered Script Execution.');
7    
8     try
9     {       
10         var filters = [.....];
11        
12         var columns = [.....];
13        
14         var results = nlapiSearchRecord('xxxxx', null, filters, columns);
15         var LOOPMARKER = nlapiGetContext().getSetting('SCRIPT','custscript_loop_marker');
16   
17         if (!isArrayEmpty(results))
18         {
19             for (var i = 0; i < results.length; i++)
20             {
21                  if (nlapiGetContext().getRemainingUsage() < 1800)
22                 {
23                     logger.debug('Rescheduling Script');
24                     var status = nlapiScheduleScript(nlapiGetContext().getScriptId(), nlapiGetContext().getDeploymentId());
25      
26                    if(status == 'QUEUED'){
27                         logger.debug('End', 'Finished Scheduled Script Due to Usage Limit');
28                         break;
29                    }
30                 }
31                
32               ...... 
33                
34                LOOPMARKER = (LOOPMARKER!=null && LOOPMARKER!=undefined) ? parseInt(LOOPMARKER) : 0
35                 var strArray = stAssociatedRecords.split(',');
36                 for (var j = LOOPMARKER; j < strArray.length - 1; j++)
37                 {
38     
39                       if (nlapiGetContext().getRemainingUsage() < 1800)
40                          {
41                               logger.debug('Rescheduling Script');
42                               var params = new Array();
43                               params['custscript_loop_marker'] = j
44       
45                               var status = nlapiScheduleScript(nlapiGetContext().getScriptId(), nlapiGetContext().getDeploymentId(),params);
46      
47                                if(status == 'QUEUED')
48                                  {
49                                      logger.debug('End', 'Finished Scheduled Script Due to Usage Limit');
50                                      break;
51                                  }
52                          }
53                        

54                       var stSOId= strArray[j].split('-')[0];
55                        var recSalesOrder = nlapiLoadRecord('salesorder', stSOId);
56                        var intLineItemCount = recSalesOrder.getLineItemCount('item');  
57                        for (var i = 1; i <= intLineItemCount; i++)
58                         {
59                             ......
60                         }
61                     
62                     nlapiSubmitRecord(recSalesOrder, false, true)
63                }                
64                 
65                 nlapiSubmitField(xxxxxx);
66             }
67             LOOPMARKER=0;
68         }
69     }
70     catch (error)
71     {
72         if (error.getDetails != undefined)
73         {
74             logger.error('Process Error',  error.getCode() + ': ' + error.getDetails());
75             throw error;
76         }
77         else
78         {
79             logger.error('Unexpected Error', error.toString());
80             throw nlapiCreateError('99999', error.toString());
81         }
82     }
83    
84     logger.debug('Exit Log', 'Exit Script Execution.');
85 }

Notes:

1. Notice that there are two if statement that checks the remaining usage limit. One for the outer for loop, and another one for the inner for loop.

2. The setup below would handle usage limit error, if the usage error would be taking place on the inner for loop. Usually, there are nested for loops on scripts because of record dependencies or better yet, logic needs to drill down further to get/change informations.

3. For line 35: var strArray = stAssociatedRecords.split(','); the inner for looping over an aray of associated records. For example, if a different use case should be encountered wherein you have actual records from a search result. Make sure you sort them by internal id.

4. Basically, the important part to note on the code would be lines:

15      var LOOPMARKER = nlapiGetContext().getSetting('SCRIPT','custscript_loop_marker'); // Initial exectution of the script, would retrieve a null or undefined value.

34       LOOPMARKER = (LOOPMARKER!=null && LOOPMARKER!=undefined) ? parseInt(LOOPMARKER) : 0 //When null or undefined, LOOPMARKER has a value of 0

43      params['custscript_loop_marker'] = j //this can be seen inside the if statement checking the usage limit of the script on the inner for loop

45       var status = nlapiScheduleScript(nlapiGetContext().getScriptId(), nlapiGetContext().getDeploymentId(),params); // assigns the params

67       LOOPMARKER=0;


No comments:

Post a Comment