api.global versus api.local

Introduction

Before using api.local or api.global, check if you can create an element for that purpose.

The api.global and api.local are hashmaps that are populated in the memory of each server node. Variable api.local is initialized to an empty Map before calculation of every item while api.global is (if the api.retainGlobal variable is set to true) initialized to an empty Map before the calculation of the first item. Old projects: If the api.retainGlobal variable is not set, then api.global behaves the same way as api.local and therefore it is deprecated practice and api.local should be used.

Calculation Flows Specifics

api.global persists between Calculation Flow (CF) logic executions and is stored within the globalFormulaState property of the CF object. If you do not want to share the global cache between logic executions, use the api.local instead, or add api.retainGlobal = false at the beginning of CF logics.
Note: api.global data in Calculation Flows (in the globalFormulaState property) is stored as a String. Use the jsonDecode(String) to convert it back to the Groovy object (a Map).

Example:

 def cf = api.find(
     "CF",
     Filter.equal("uniqueName", "ScheduleCalculations"),
     Filter.equal("draft", "false")
 ).first()

 def config = api.jsonDecode(cf.configuration).entries.get(0)?.globalFormulaState

 return config.lastCalculationDate

Usage examples are documented at Caching Strategies in Configuration.

If any of the variables api.global or api.local holds a lot of data, these variables should not be returned as an element result since the data gets usually persisted for each calculated record.

api.global

By setting api.retainGlobal = true you can instruct the formula engine to keep the hash map in between logic runs. It works between line items and, in case of Quotes, Agreements/Promotions, Rebate Agreements and Claims, between the header and the line items (but only in the pre-phase, not in the post-phase). The values are also carried forward between two list calculation passes (i.e., form initial run to dirty item run; ONLY in non-distributed mode.).

Remember that for distributed calculations api.global is populated on each server node and each thread independently. So if you store there the results of some data queries, those queries will get executed on every node (and not once as one may think).

You should always:

  • Cache some reasonable amount of data to be used for multiple items. Storing big data causes bad performance when recalculating a single item.
    (info) Since Vesper 6.0, the maximum string size of JSON serialized api.global content that is passed on to dirty passes is limited to 2MB. This is configurable in pricefx-config.xml (maxGlobalsSize).
  • Define a constant to be used in many elements of the logic.

When api.global should not be used:

  • For passing values to functions. These functions would later become difficult to use. Consider passing values to a function as regular function parameters.


For old projects created before Manhattan 4.0 release: make sure api.retainGlobal is set to true by default. Since if not set, the variable to true in the first element of the logic; otherwise the value of api.global will get lost. This was a common error that caused performance issues when values which should be cached for all items were calculated for every item.


(info) See also:

api.local

Before using api.local, consider creating a new element (possibly with the Display option = None) and store the value there. Performance-wise it is identical since both api.getElement and api.local are represented by HashMaps. You will also debug the value more easily: as elements result(s) of a logic test. You also will not need to call api.trace to debug the value. Last but not least, it will also help you avoid potential naming clash of the api.local key.

So api.local should be used only in the following scenarios:

  • If you set api.local in some element and you then need to change the value in some other element (try to avoid it though).
  • You need to store multiple calculated values and you do not want to return Maps as an element result. For example, you calculate a price at certain place and want to set a price reason text at once. In that case, the element typically returns the price and sets the price reason as e.g., api.local.reason.

When api.local should not be used:

  • For passing values to functions. These functions would later become difficult to use. Consider passing values to a function as function parameters.

Found an issue in documentation? Write to us.