Business Rule Elements to Use

This is one of the recommendations for performing analysis on business rule to improve performance. The full list is defined in the Business Rule Analysis topic here.

The following list includes business rule elements known to assist system performance. This list can be used to troubleshoot existing long-running business rules, and can also be reviewed prior to writing new business rules to prevent performance problems.

Use Exception Handling

If an error occurs during approval, an exception is thrown from the domain layer. If this exception is caught in a business rule but not re-thrown, it will not reach the exception approval handler. In this case, objects can be inconsistently approved (some parts are approved and other parts are not). This behavior also has a negative effect on the performance of the business rule.

When writing JavaScript business rules, it is important that 'try…catch' statements are designed correctly. 'Try...catch' statements should not swallow (catch and ignore) exceptions that should cause changes made by the script to be rolled back and cause the business rule to fail.

Additionally, only catching an exception without rethrowing it can lead to inconsistent data or the error: 'The transaction cannot be committed, because it was already marked for rollback only. The transaction will be rolled back instead.'

Important: Carelessly catching and ignoring exceptions will lead to derived errors, which usually makes it difficult to determine the root cause.

The sample code in the table below demonstrates a way to log exceptions in JavaScript without swallowing those that should be handled by the framework.

Correct

Incorrect

try {
     // Some code
} catch (e) {
	logger.info(e);
          throw(e); // REQUIRED
}
try {
	// Some code
} catch(e) {
	logger.info(e);
 
}

The only types of JavaScript exceptions that may be caught and handled locally are:

  • Checked exceptions thrown by an invoked method (including any subclasses of the specified checked exception) (refer to the example below)
  • Exceptions not generated by calls to the STEP API

Important: Any other exception must always be re-thrown if caught, or not caught at all.

Correct Handling of Checked Exceptions

The code snippet below demonstrates how a checked exception can be caught and handled locally, including the necessary Rhino specific 'e.javaException' notation.

Copy
try {
currentObject.createReference(targetAsset, primaryImageRefType.getID());
} catch (e) {
if (e.javaException instanceof com.stibo.core.domain.UniqueConstraintException) {
logger.info("Reference could not be created");
} else {
throw(e); // All other exceptions MUST be re-thrown
}
}       

Proper exception handling correctly re-throws the exception when using 'try-catch' in business rules and avoids inconsistent objects.

For more information, refer to the Recommended Error Handling Practices topic of the Resource Materials section of online help here.

Use Logging Carefully

Warnings and errors encountered while executing business rules can be written in the Main STEP Log File. While logging many details can have a negative impact on performance, using the correct logging level can aid in troubleshooting and resolving unexpected outcomes.

Logging can be managed for all business rules or on a per-business rule basis.

Manage Logging for all Business Rules

Define the appropriate logging level for each STEP server environment using the following case-sensitive entries in the sharedconfig.properties file:

  • BusinessRule.Warning.Threshold - a threshold in milliseconds for business action execution. If it takes longer to execute or test a given business action, a warning is posted in the Main STEP Log File.

For example, the following setting writes a warning to the STEP log file whenever a business rule execution takes longer than 10 seconds.

BusinessRule.Warning.Threshold=10000
  • Log.Level - specifies the level of detail for logging business rules results, the entry shown below would include log entries for info, warning, and severe:
Log.Level = INFO
  • Log.Level.org.mozilla.javascript.MemberBox - specify the logging level for business rule results, as shown below:
Log.Level.org.mozilla.javascript.MemberBox = SEVERE 

The logging values are ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, and OFF. The most granular logging provided using ALL, while minimal logging is written using SEVERE. Setting a level also includes logging for the levels to the right. INFO is the default setting.

Suggested settings are FINE to trace errors on a development or test system, INFO or WARNING for a QA system, and SEVERE on a production system.

Manage Logging per Business Rule

Log the result of business rules during development on the development server, but turn off the logging when deploying to the test, quality, and production servers. An easy and transparent way to control logging per business rule is to set a debug flag in the business rule code, as illustrated below.

//Debug 'flag' DO NOT use unless you develop or test
//When doing tests DO NOT test on large amount of products
//REMEMBER to set to 'false' when development and testing phases are complete
var isDebug = false;
			
//Function to handle whatever logging of debug information should occur or not
function logDebug(message) {
if(isDebug) {logger.info(message)}
}
...
logDebug("A message for the log file")
...

Use Arrays, Not Multiple Read Calls

Business rules repeatedly using calls to the database for large sets of data significantly degrades performance. Instead, use one call to get the data, and push it into arrays and work from there. Minimizing the number of calls to the database aids performance.

When multiple business rules are executed sequentially (e.g., as part of an approval process), and these business rules fetch the same data from the database multiple times, it is beneficial to rewrite the business rules to fetch the data once, and push the data into (multi-dimensional) arrays.

In-Memory

In-Memory can improve performance of the business rules because it provides faster operations on complex data models where business rules navigate references.

In-Memory may improve performance on business rules that still perform poorly after implementing the recommended practices for business rules. For more information, refer to the In-Memory Database Component for STEP topic of the Resource Materials section of online help here.

Consider Using an Extension

An extension should be considered when additional performance improvement on business logic in the system is required and all previous recommendations on business rules are implemented (including In-Memory). Some of the code using in JavaScript (business rules) might run faster in Java (extensions).

Important: Only cases where extreme amounts of logic are executed should be considered for this solution. And in such cases, first consider why it is necessary to run such complex logic.

For example, you could develop a custom extension instead of executing many complex business rules on import of data. The possible benefits of such a solution are:

  • Event batching is used by the processor to ensure that business logic is executed exactly once per product per batch, even if multiple or many imports are executed for a single product.
  • The example plugin optionally uses the parallel processing framework to maximize performance. Potentially, this allows a ‘strict’ transaction endpoint to benefit from parallelization in that rule execution can be multi-threaded while still ensuring data integrity.
  • Optimistic locks and deadlocks can be resolved in cases where the locks are caused not by the import itself, but by logic that accesses and writes to objects shared among parallel import processes.

A common example of this occurs with tree structures. If parallel imports are executing on children of a common parent, each of which executes business logic causing an update to the parent, deadlocks (and sever performance degradation) will result.

Another performance-related issue with this pattern is that the business logic is executed once per child. However, if the import logic is changed to republish the parent to the event queue instead of each child, event batching will result is a single update to the parent object, regardless of the number of children imported.

  • For STEP 7.4+ solutions, the same concept can be applied using an outbound integration endpoint configured with a business rule pre-processor. First, execute import business logic in the pre-processor, then discard the event so that no exports are produced by the endpoint.

Note: Endpoints do not use multithreading while executing the pre-processor so the execution time may be longer than if a custom extension is used.

However, a pre-processor solution also has some consequences:

  • There will be a delay between importing data onto the object and the business rule running. If timing is an issue, consider another option.
  • Running business rules in a pre-processor does not allow the object to be inspected in both its previous and current form as easily as running the same rule running during import.