Neu Performance NOVA: io Flut

Aaron

Sehr aktives Mitglied
25. Oktober 2012
260
30
Hallo Zusammen,

WORUM ES GEHT

Auf Kategorieseiten in der Listenansicht setzt der Shop bei jedem Seitenaufbau einen POST an /io pro gelistetem Artikel ab. Bei "Artikel pro Seite = 50" sind das rund 50 Anfragen für einen einzigen Seitenaufruf, jede mit eigener PHP-Instanz und eigener Datenbankverbindung.

Auf einem Shared- Hosting-Paket reicht das aus, dass ein einzelner Besucher
max_user_connections sprengt. Der Shop antwortet dann mit

SQLSTATE[HY000] [1203] User <db> already has more than 'max_user_connections' active connections

Ich möchte nicht behaupten, dass das ein Fehler ist - der Code prüft ausdrüclich auf Listenseiten, das ist also offenbar so gedacht. Meine Frage ist, ob auch der sofortige Aufruf dort beabsichtigt ist, oder ob er sich auf Artikeldetailseiten begrenzen liesse.

DIE STELLE

templates/NOVA/js/jtl.article.js, Zeilen 381-398 (Fassung 5.6.0):

Code:
381 |  registerBulkPrices: function($wrapper) {
  382 |      var $bulkPrice = $('.bulk-price', $wrapper),
  383 |          that       = this,
  384 |          $config    = $('#product-configurator');
  385 |
  386 |      if (($bulkPrice.length > 0 && $config.length === 0) || $('#product-list').length > 0) {
  387 |          $('#quantity, [data-bulk="1"] .quantity', $wrapper)
  388 |              .each(function(i, item) {
  389 |                  let $item   = $(item),
  390 |                      wrapper = '#' + $item.closest('form').closest('div[data-wrapper="true"]').attr('id');
  391 |
  392 |                  $item.on('change', function () {
  393 |                      that.variationPrice($(this), true, wrapper);
  394 |                  });
  395 |                  that.variationPrice($(this), true, wrapper);
  396 |              });
  397 |      }
  398 |  },

Zeile 393 steht im change-Handler - das ist klar und richtig.
Zeile 395 steht ausserhalb und laeuft damit fuer jedes gefundene Element
sofort beim Seitenaufbau.

variationPrice() (ab Zeile 1671) ruft in Zeile 1682
io.call('checkDependencies', [args], ...) auf - also ein POST an /io.

Warum das auf Listenseiten je Artikel greift

- Zeile 386: $('#product-list').length > 0 ist auf Kategorieseiten immer
wahr; NOVA/productlist/index.tpl vergibt id="product-list".

- Zeile 387: [data-bulk="1"] .quantity trifft jede Artikelzeile, weil
NOVA/productlist/item_list.tpl je Artikel setzt:
{inputgroup class="form-counter" data=["bulk" => {!empty($Artikel->staffelPreis_arr)}]}

- Aufrufkette: Zeile 1756 $(document).ready(... register()) -> Zeile 122
this.registerBulkPrices($wrapper) - die steht ausserhalb des
if (this.isSingleArticle())-Blocks (ab Zeile 52) und laeuft daher auf
allen Seitentypen.

Die Kachel-/Galerieansicht ist nicht betroffen: item_box.tpl enthält kein Mengenfeld, der Selektor greift dort nicht.

NACHSTELLEN

1. Kategorie mit mindestens 50 Artikeln, Darstellung "Liste",
Artikel pro Seite = 50
2. Browser -> F12 -> Netzwerk -> Filter auf "io" -> Seite neu laden

Gemessen an einem Produktivshop (~15.000 Artikel, Shared Hosting):

Artikel pro Seite POST an /io davon HTTP 500
------------------------------------------------------------
50 49 42
12 12 0
50, data-bulk entfernt 0 0
Artikeldetailseite 1 0

Die 500er sind hier keine Programmfehler, sondern abgewiesene
Verbindungen - alle Antworten exakt 100 Byte, Laufzeit 0 Sekunden.

--------------------------------------------------------------------------

WIRKUNG IM BETRIEB

Aus dem Zugriffsprotokoll eines Tages (325.704 Zeilen). Fehlerquote der
/io-Aufrufe, gruppiert nach der Zahl gleichzeitiger /io in derselben
Sekunde:

/io je Sekunde Aufrufe Fehler 500 Quote
----------------------------------------------------
1-9 31.167 78 0,25 %
20-29 11.147 576 5,17 %
40-49 4.140 1.135 27,42 %
60+ 1.063 519 48,82 %

Ein Besucher, der eine 50er-Kategorieseite oeffnet, landet mit seinen
49 Anfragen im Alleingang in der Zeile "40-49".

Vergleich mit einem Tag vor dem Update, dieselben 22 Kategorieseiten:

16.02.2026: 2.279 Seitenaufrufe -> 22 /io-Anfragen
24.08.2026: 2.266 Seitenaufrufe -> 28.962 /io-Anfragen!

MEINE FRAGE


Ist der sofortige Aufruf in Zeile 395 auf Listenseiten so beabsichtigt?

Auf einer Artikeldetailseite ist er unaufällig- ein Aufruf. Auf einer Liste mit 50 Artikeln werden daraus 50 gleichzeitige Datenbankverbindungen, und das ist auf einfachem Hosting mehr, als ein Paket hergibt.

Ggf. wäre ein Hinweis hinter dieser Einstellung auch hilfreich.

Falls er nur für Detailseiten gedacht war, wäre das nur eine kleine Anpassung.

UMGEHUNG, FALLS JEMAND DASSELBE PROBLEM HAT

Am besten im Kind-Template templates/<child>/productlist/item_list.tpl das Attribut fest auf false setzen.
Der Selektor [data-bulk="1"] .quantity trifft dann nichts mehr, #quantity gibt es nur auf der Artikeldetailseite.

Was das kostet: In der Liste aktualisiert sich der Staffelpreis nicht mehr automatisch, wenn dort die Menge geaendert wird. Artikeldetailseite funktioniert das unverändert.

Man kann den Warenkorb-Button auch in den Template-Einstellungen deaktivieren für die Artikellisten-Seiten.

Viele Grüße