Friday, November 25, 2011

Regarding ConcurrentUpdateException and InvalidVersionException

There are 3 places where order version is stored
1) Database level - dcspp_order.version
2) Repository item cache level - orderItem.getPropertyValue("version");
3) Session level - order.getVersion();

// This check is done in classes where order is modified
if (order.getVersion() != orderItem.getPropertyValue("version"))
     throw atg.commerce.order.InvalidVersionException

// This check is done while updating item
if (dcspp_order.version != orderItem.getPropertyValue("version"))
      throw atg.repository.ConcurrentUpdateException

Note: concurrency can be maintained on any repository item, please go through below documentation
http://docs.oracle.com/cd/E26180_01/Platform.94/RepositoryGuide/html/s0709maintainingitemconcurrencywithth01.html

atg.repository.ConcurrentUpdateException - Is thrown if 2 separate sessions (belong to 2 different instances) of same user edit same order simultaneously or if 2 applications are editing same order. One way to reproduce in cluster environment (in production)
Login in one browser 1  with one user suppose xyz and logout
Login in another browser 2  with same user xyz and logout
Login back in browser 1 with same user xyz

This exception is thrown in logs of instance (browser 1 session instance)
CONTAINER:atg.commerce.CommerceException; SOURCE:CONTAINER:atg.service.pipeline.RunProcessException: An exception was thrown from the context of the link named [updateCommerceItemObjects].; 
SOURCE:CONTAINER:atg.commerce.CommerceException: Saving order 2288449002 failed because doing so would result in data being overwritten. This save attempt had an out of date repository item [commerceItem].; 
SOURCE:atg.repository.ConcurrentUpdateException: no rows updated oldVersion=20 for item=commerceItem:ci55251446 in GSATransaction=atg.adapter.gsa.GSATransaction@6a77cca2    
thread=ajp-10.238.160.131-30100-37 transaction=TransactionImple < ac, BasicAction: aeea083:6d44:4ecb6eb0:da1fd5 status: ActionStatus.RUNNING >
Note: Typically item-cache-timeout by default is -1 (when not set) which means item will be in cache until invalidated. Suppose the item-cache-timeout for order is set to 30 mins.

Explanation -
When the user xyz login in one browser 1
  suppose his/her session is tied to one instance 1 and suppose his order version is incremented to 2.
logout
Note that user xyz order is cached in this instance 1 and its version is 2 and it will be there in the cache until item-cache-timeout which is 30 mins.

If the same user xyz tries to login using another browser 2
  suppose his/her session now got tied to another instance 2 and his order version will be incremented to 3.
logout
Note that user xyz order is cached in this instance 2 and its version is 3 and it will be there in the cache until 30 mins

since orderRepository has simple cache, instance 1 has no idea of updated version.
Note: If the browser 1 cookies are not removed, request will always go to instance 1.
In this 30 mins time, when user xyz login using browser 1, at the time of loadorder since the version in cache (which is 2) doesnt match with version in database
(which is 3) ConcurrentUpdateException is thrown.

This can also happen if the user in application like CSC and dotcom user both working on same order, then above exception is thrown

atg.commerce.order.InvalidVersionException -  is caused if 2 sessions (of same instance) of same user modifying same order simultaneously. 
One way to reproduce in dev environment (only 1 instance) or you need to make sure that 2 sessions belongs to same instance in cluster environment.

If the user has 2 seperate session in 2 seperate browsers, where both sessions are tied to one instance and since both session are updating same order, InvalidVersionException exceptions is thrown.

Explanation -
Whenever the order is updated, both order (session) version and order repository version are updated.
When updating if both order version and order repository version are not equal, then invalid version exception is thrown.

**** Error      Fri Nov 25 15:08:57 CST 2011    1322255337883   /atg/commerce/order/purchase/RepriceOrderDroplet        ---
CONTAINER:atg.service.pipeline.RunProcessException:
An exception was thrown from the context of the link named [updateOrderAfterReprice].; SOURCE:atg.commerce.order.InvalidVersionException: This order (2293186179) is out of date.
Changes have been made to the order and the operation should be resubmitted. Order version 4, Repository item version 9.
        at atg.service.pipeline.PipelineChain.runProcess(PipelineChain.java:371)
        at atg.service.pipeline.PipelineChainContext.runProcess(PipelineChainContext.java:185)
        at atg.service.pipeline.PipelineManager.runProcess(PipelineManager.java:453)
        at atg.service.pipeline.servlet.PipelineChainInvocation.service(PipelineChainInvocation.java:267)
        at atg.commerce.order.purchase.RepriceOrder.service(RepriceOrder.java:438)
        at atg.servlet.DynamoServlet.service(DynamoServlet.java:123)
        at atg.taglib.dspjsp.DropletTag.invokeServlet(Unknown Source)
        at atg.taglib.dspjsp.DropletTag.doAfterBody(Unknown Source)
        at org.apache.jsp.checkout.shippinginfo_jsp._jspx_meth_dsp_005fdroplet_005f8(shippinginfo_jsp.java:2128)
....stack trace CROPPED after 10 lines.
Caused by :atg.commerce.order.InvalidVersionException: This order (2293186179) is out of date. Changes have been made to the order and the operation should be resubmitted. Order version 4, Repository item version 9.
        at atg.commerce.order.OrderManager.updateOrder(OrderManager.java:2557)
        at atg.commerce.order.processor.ProcUpdateOrder.runProcess(ProcUpdateOrder.java:111)
        at atg.service.pipeline.PipelineLink.runProcess(PipelineLink.java:233)
        at atg.service.pipeline.PipelineChain.runProcess(PipelineChain.java:343)
        at atg.service.pipeline.PipelineChainContext.runProcess(PipelineChainContext.java:185)
        at atg.service.pipeline.PipelineManager.runProcess(PipelineManager.java:453)
        at atg.service.pipeline.servlet.PipelineChainInvocation.service(PipelineChainInvocation.java:267)
        at atg.commerce.order.purchase.RepriceOrder.service(RepriceOrder.java:438)
        at atg.servlet.DynamoServlet.service(DynamoServlet.java:123)
....stack trace CROPPED after 10 lines.

5 comments:

  1. It was very clearly explained thanks... also i have seem similar error in BCC concurrentModificationExceptions.. do you think this is anything on the same line?

    ReplyDelete
  2. Just wanted to ask one thing, how can we check the current order's session version?

    ReplyDelete
  3. ConcurrentUpdateException can also happen on AJAX requests triggering updates to order. AJAX for same user and same instance can have racing update conditions triggering concurrency on the update actions.

    ReplyDelete
  4. 1. How to overcome ConcurrentUpdateException?
    2. Is there any solution other than using No caching or Distributed caching or Locked caching ?

    ReplyDelete