cancel
Showing results for 
Search instead for 
Did you mean: 

Concurrent modifications of the same cart object from different HTTP sessions result in "object no longer valid" exception

former_member981644
Participant
0 Kudos
1,800

Hi,

Getting below exception when doing concurrent modifications of the same cart.

 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 | SEVERE: Servlet.service() for servlet [DispatcherServlet] in context with path [/yb2bacceleratorstorefront] threw exception [Request processing failed; nested exception is item 8796095414316 no longer valid (was removed): object no longer valid] with root cause
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 | item 8796095414316 no longer valid (was removed): object no longer valid
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.Item$CachedGetter.get(Item.java:690)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.ExtensibleItem.getProperty(ExtensibleItem.java:363)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.order.GeneratedAbstractOrderEntry.getDiscountValuesInternal(GeneratedAbstractOrderEntry.java:268)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at sun.reflect.GeneratedMethodAccessor1572.invoke(Unknown Source)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at java.lang.reflect.Method.invoke(Method.java:497)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.type.ReflectionAttributeAccess$AttributeMethod.invokeGetter(ReflectionAttributeAccess.java:739)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.type.ReflectionAttributeAccess.getValue(ReflectionAttributeAccess.java:944)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.Item.getAttribute(Item.java:1850)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.internal.model.impl.JaloPersistenceObject.readRawValue(JaloPersistenceObject.java:109)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.internal.converter.impl.ItemModelConverter.readSingleAttribute(ItemModelConverter.java:1371)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.internal.converter.impl.ItemAttributeProvider.getAttribute(ItemAttributeProvider.java:108)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.model.ItemModelContextImpl.loadUnlocalizedAttribute(ItemModelContextImpl.java:285)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.model.ItemModelContextImpl.getValue(ItemModelContextImpl.java:245)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.model.ItemModelContextImpl.getPropertyValue(ItemModelContextImpl.java:261)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.core.model.order.AbstractOrderEntryModel.getDiscountValuesInternal(AbstractOrderEntryModel.java:296)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.order.AbstractOrderEntryDiscountValuesAttributeHandler.get(AbstractOrderEntryDiscountValuesAttributeHandler.java:27)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.jalo.order.AbstractOrderEntryDiscountValuesAttributeHandler.get(AbstractOrderEntryDiscountValuesAttributeHandler.java:1)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.internal.model.attribute.impl.DefaultDynamicAttributesProvider.get(DefaultDynamicAttributesProvider.java:45)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.servicelayer.model.ItemModelContextImpl.getDynamicValue(ItemModelContextImpl.java:344)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.core.model.order.AbstractOrderEntryModel.getDiscountValues(AbstractOrderEntryModel.java:286)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.282 |     at de.hybris.platform.commercefacades.order.converters.populator.AbstractOrderPopulator.getProductsDiscountsAmount(AbstractOrderPopulator.java:494)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.commercefacades.order.converters.populator.AbstractOrderPopulator.addPromotions(AbstractOrderPopulator.java:472)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.commercefacades.order.converters.populator.CartPopulator.addPromotions(CartPopulator.java:59)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.commercefacades.order.converters.populator.AbstractOrderPopulator.addPromotions(AbstractOrderPopulator.java:457)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.commercefacades.order.converters.populator.CartPopulator.populate(CartPopulator.java:42)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.commercefacades.order.converters.populator.CartPopulator.populate(CartPopulator.java:1)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.converters.impl.AbstractPopulatingConverter.populate(AbstractPopulatingConverter.java:73)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.converters.impl.AbstractConverter.convert(AbstractConverter.java:41)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.commercefacades.order.impl.DefaultCartFacade.getSessionCart(DefaultCartFacade.java:108)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.yb2bacceleratorstorefront.controllers.pages.CartPageController.getQuoteUrl(CartPageController.java:159)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.yb2bacceleratorstorefront.controllers.pages.CartPageController.prepareCartUrl(CartPageController.java:144)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at de.hybris.platform.yb2bacceleratorstorefront.controllers.pages.CartPageController.showCart(CartPageController.java:139)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at sun.reflect.GeneratedMethodAccessor9692.invoke(Unknown Source)
 INFO   | jvm 1    | main    | 2017/10/25 16:31:56.304 |     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)....


Here is the detailed steps to reproduce the issue:

  1. Add multiple products to a cart while logged in.

  2. With two different persons using two PCs log into the same account, where the products have been added to the cart.

  3. Let one person remove product by product from the cart.

  4. Let the second person refresh the cart page at rapid rate.

Thanks in advance!!

Accepted Solutions (0)

Answers (2)

Answers (2)

petervangestel
Explorer

You should extend DefaultCommerceCartCalculationStrategy and synchronize on the cartModel. This applies to calculateCart() and recalculateCart().

 @Override
 public boolean calculateCart(final CommerceCartParameter parameter) {
         final CartModel cartModel = parameter.getCart();
         validateParameterNotNull(cartModel, "Cart model cannot be null");
         synchronized (modelService.getSource(cartModel)) {
             // maybe try / catch needed
             super.calculateCart(parameter); 
     }
 }

Overriding the alias makes your class being used as commerceCartCalculationStrategy

 <alias alias="commerceCartCalculationStrategy" name="synchronizedCommerceCartCalculationStrategy"/>
 <bean id="synchronizedCommerceCartCalculationStrategy"
           class="com.osudio.hybris.facades.order.impl.SynchronizedCommerceCartCalculationStrategy"
           parent="defaultCommerceCartCalculationStrategy"/>

Update: One addition to this. If you run multiple nodes in a cluster without sticky sessions, this solution is insufficient. In that case synchronized needs to be replaced by a database lock on the cart.

 modelService.lock(cartModel.getPk());

It is important that this happens within a transaction (@Transactional) or

 Transaction.current().begin(); 
 try {
     modelService.lock(cartModel.getPk());
     // do calculation stuff 
     Transaction.current().commit();
 } catch() {
     Transaction.current().rollback();
 }
manish_sethi
Associate
Associate
0 Kudos

Hi,

Did you get any solution for this issue. I also have a similiar scenario and we are stuck up with the same issue

Regards, Manish

former_member631591
Discoverer
0 Kudos

Is there any solution for this issue ? We are facing the same issue.

Thanks.