Iteration and Transaction Boundaries

When iterating over objects, make sure that you retrieve the object as part of the same transaction that acts on the object. Otherwise, B2C Commerce returns an error to prevent you from accidentally overwriting the object with stale data.

Updating Objects Using Iterators

If a node has the Transactional property set to True, it executes as a separate transaction. Script nodes, by default, have the Transactional property set to true.

To successfully update objects, you can use one of the following methods:

Method 1: commit each object in a separate Transaction

Identify all objects to update, retrieve each object one at a time, and then update each object in a separate transaction. We recommended this method for updating objects.

An example is a pipeline that does the following:
  1. Assign node From_0 dw.catalog.ProductMgr.queryAllSiteProducts() To_0 products
  2. Loop node that iterates through products where the element key is CurrentProduct and the iterator key is products
    1. GetProduct pipelet node supplies a ProductID of CurrentProduct.ID to retrieve a Product
    2. Script pipelet node runs ScriptFile UpdateProducts.ds, a custom script file, which opens a transaction, updates the Product, and commits the transaction.
Note: If you use this method, it's important to be aware if a transaction removes or modifies an object. If the object is referenced in later transactions, it might not exist.

Method 2: commit in a single Transaction

Update all objects in a single transaction. Use this method if you have only a few objects to update and you want changes to be made to all or none of the objects.

An example is a pipeline that does the following:
  1. Assign node From_0 dw.catalog.ProductMgr.queryAllSiteProducts() To_0 products
  2. Script pipelet node runs ScriptFile UpdateProducts.ds, a custom script file, which opens a transaction, iterates through each product, updates it, and commits the transaction.
Note: If you use this method, it's important to be aware that:
  • the transaction might become large, with a risk of exceeding the allowed transaction size and using a large amount of system resources.
  • the transaction commit might fail due to other concurrent threads. If the commit fails, none of the objects are updated.

Reusing Iterators

As a best practice, do not reuse the same iterator in multiple pipelets in the same pipeline. Doing so can cause an IllegalStateException: Iterator is invalid error.

Iterators in this state don't return accurate results. Any attempt to use them results in a WARN log message that says Iterator is invalid. Scripts and pipelines that generate this error should be rewritten to ensure that they generate correct and complete results.

For example:
  1. The SearchSystemObject pipelet creates a SearchResult iterator.
  2. The ExportCustomers pipelet uses that iterator to export the results to a file. As a side effect, the iterator moves to the end of the collection.
  3. A second pipelet attempts to use the same iterator. At this point, the iterator has been consumed so a warning is logged, and the results are inconsistent.

The correct way to reuse iterators is to repeat the SearchSystemObject step so that the second pipelet gets a fresh iterator.