Today I was finally able to fix a pretty significant issue we were seeing at work. Over the past few weeks (really probably the last 6-8 weeks but it really showed its ugly head in the last 7 to 10 days) the time it was taking to add a product to cart was taking an incredibly long time (like 30 – 90 seconds). Obviously this can absolutely destroy conversion.
The problem did not just stop there. The entire checkout process was taking forever. Basically anytime Magento tried to touch the cart object it was slow.
The first thing we did (a few weeks ago) was to separate out the “Add to Cart” action and the “Redirect to Cart Page” action. The reason for this was that we were noticing that there was about 2-3 seconds where “nothing” was happening. Ajaxing the add to cart action seemed to handle this problem. Really all it did was buy me a few weeks before the problem appeared again.
Fast forward about 3ish weeks and I am getting complaints from customer service that customers are getting an error message when they try to add to cart (but the item goes in to their cart when they reload the page). Sure enough, under certain circumstances, the ajax would time out. So I increased the time before the timeout and started casually investigating (not thinking it was a major issue but more of a fringe case).
Then early this week we noticed it was not just the add to cart action, but rather the entire checkout process. Now it’s priority number one.
The first thing I did was try to find where the slowdown actually was. A quick look in the cart controller showed me that the slow down was happening in the cart object’s “save” method. That was odd I thought. Really all that should be doing is saving the session. Perhaps there is an issue with that. Since our sessions are saved to the file system I figured maybe there is some lag in the seek time on the hard drive. There are after all, between 70-120 customers on the website at any given time. That is a lot of reading and writing. So I decided I was going to try moving the session save to the database. This is something that just had to be done in the middle of the night since I did not want to logout everyone in the admin panel, while simultaneously emptying every customers cart (that is just bad for business and I did not want to hear about all the calls that customer service got). So I woke up about 4:30 this morning to make the big switch over. There was no change in the add to cart time at all. So I switched back to saving the sessions in files (since in my mind the next step was to try using tmpfs for the session storage).
I was about to have our webhost setup tmpfs, then I had a thought. What if it was not the hard drive write speed that was slow? What if it was something else? In the past few weeks we had implemented some new things like proper sales tax calculation for California. It was time to dig into code some more.
So I followed the cart object save method to the quote object. There was a collectTotals method in there which then took me to the quote address object which had a collectTotals method as well. Now inside this collectTotals method there was a for loop that iterated through all the different kinds of order total classes in Magento. As it turns out there were two methods that were taking the entire amount of time to add to cart. One was dealing with Free Shipping and one was dealing with Discounts. That is when it hit me!
In the past weeks we had implemented a method of doing multi-unit discount by creating a lot of Shopping Cart Price Rules (By a lot, I think it is safe to say around 40 to 50). So I created a script very quickly to disable all of these rules in hopes that it would fix the problem.
Sure enough it did.
The good news is that our customers can now add to cart at a reasonable speed (about 1 second), the bad news is that we need a new strategy for mult-unit discounts. In the end the greater good for the company was to give everyone a good checkout experience over a lower price for the few people that use the multi-unit discount.