Pragnieniem każdego właściciela sklepu internetowego jest posiadanie serwisu, który działał szybko i sprawnie, a jak wiadomo czynniki te wprost wpływają na konwersje i zadowolenie klientów.
Platforma Adobe Magento Open Source używa systemu cache'owania, który sprawia, że strona ładuje się szybciej, a serwer jest mniej obciążony. W magento Open Source cache’owane są strony produktów, kategorii i strony cms. Strony te wyglądają tak samo dla każdego użytkownika odwiedzającego sklep, zaś ich zawartość po wygenerowaniu przez serwer jest przechowywana w pamięci. Kolejni odwiedzających otrzymują w ten sposób wcześniej zapisana zawartość (content nie jest generowany każdorazowo dla każdego usera). Mechanizmy Magento Open Source automatycznie usuwają cache z pamięci, jeżeli zawartość się zmieni, np: przez edycję produktu lub kiedy produkt zostanie wyprzedany.
Opis sytuacji wyjściowej
Strony kategorii w Magento Open Source są jednymi z najbardziej obciążających serwer, a jednocześnie bardzo często odwiedzanych stron. Cache tych stron odświeżane są za każdym razem, gdy dany produkt zostanie wyprzedany. Wynika to z faktu, że produkt ma się już więcej nie pokazywać lub był oznaczony jako niedostępny.
Zespół developerski Alekseon zauważył, że cache kategorii w Magento Open Source jest odświeżany także w momencie, gdy zostanie wyprzedany produkt, który nie jest widoczny pojedynczo, a jedynie reprezentuje opcję produktu konfigurowalnego (np rozmiar). W takim przypadku usuwany jest cache wszystkich kategorii, w których znajduje się produkt konfigurowalny, a w przypadku wielu stron nie ma to wpływu na zawartość stron kategorii.
W praktyce okazuje się, że cache stron kategorii usuwany jest bardzo często, przez co klienci trafiają na stronę kategorii bez zbudowanego cache’a. Taka strona otwiera się wolniej oraz obciąża serwer w większym stopniu.
Co zmieniliśmy?
W sklepach naszych klientów zastosowaliśmy poprawkę, która w zauważalny sposób wpłynęła na poprawienie wydajności i szybkości ładowania stron. Przestaliśmy odświeżać cache kategorii w przypadku, gdy zmienił się jedynie status magazynowy produktu, który nie jest widoczny pojedynczo.
Kto najmocniej na tym skorzysta?
Najwięcej zyskają sklepy, które:
- używają produktów niewidocznych pojedynczo jako opcji produktów konfigurowalnych
- posiadają kategorie z dużą ilością produktów (duża liczba SKU)
- posiadają produkty z niewielką ilością magazynową
- mają duży ruch i częstą sprzedaż
- często doświadczają stock-outów
Warto pamiętać przed wdrożeniem - efekt uboczny
Niestety w niektórych przypadkach nasza poprawka ma swoje konsekwencje:
- lista filtrów kategorii może być nieaktualne, jeżeli ich wartości są zależne od produktów niewidocznych pojedynczo, np kiedy mamy filtr dostępnych rozmiarów. (Nie wpływa to na wynik filtrowania)
- jeżeli wyświetlamy opcje produktów na kategorii, to mogą być one nieaktualne. (Na stronie produktu będą poprawne)
Jak zainstalować poprawkę
Nasza poprawka jest darmowa i dostępna na githubie.
https://github.com/Alekseon/magento2-category-cache-cleaner-improvementPo zainstalowaniu należy ją włączyć w konfiguracji Magento:
stores -> Configuration -> Catalog -> Cache -> Refresh the Category Cache only if stock status changed for visible products
Uwagi techniczne
Nadpisaliśmy natywną klasę Magento Open Source przez preferencję w di.xml:
Magento\CatalogInventory\Model\Indexer\Stock\CacheCleaner
Naszym celem była modyfikacja parametru $productIds przekazywanego do metody
getCategoryIdsByProductIds($productIds) w metodzie clean(...):
$productIdsForCategoryCacheClean = $this->getProductIdsForCategoryCacheClean($productStatusesBefore, $productStatusesAfter); $categoryIds = $this->getCategoryIdsByProductIds($productIdsForCategoryCacheClean);
Natywna klasa CacheCleaner posiada poniższe metody prywatne które musieliśmy skopiować, ale nie zawierają żadnych naszych zmian:
private function getProductStockStatuses(array $productIds) private function getProductIdsForCacheClean(array $productStatusesBefore, array $productStatusesAfter) private function getCategoryIdsByProductIds(array $productIds) private function getConnection()