ceske-sluzby
ceske-sluzby copied to clipboard
XML feedy velké množství produktů 20k+
Narazil jsem na problém u jednoho shopu, který má kolem 20 tisíc produktů. I když má 256 MB memory limit, tak je pořád hláška memory exhaust.
Tak 20 tisíc jsem tedy nezkoušel :-) Můžete zkusit, zda se nevygeneruje ani soubor pro Pricemania? Ten je generován trochu jiným způsobem, který by měl být trochu úspornější...
To bohužel nejde, protože při aktivaci xml se shodí kompletně celý web, včetně frontendu.
Tak jsem zakomentoval heureku a zbozi, spustil jen pricemania a chyba se změnila. Feed vygeneruje, ale je chyba s parsováním.
Chyba parsování XML: Nenalezen žádný prvek
Adresa: http://domena.cz/obsah/pricemania.xml
Řádek 73982, sloupec 1:
Po aktivaci feedů dojde automaticky k vygenerování souboru pro Pricemania: https://github.com/pavelevap/ceske-sluzby/blob/master/ceske-sluzby.php#L399
A tam patrně dojde k problému s pamětí. Ostatní feedy by měly být zpracovány pouze v případě, když si je někdo zobrazí.
Chyba parsování může souviset s tím, že skript někde skončil kvůli nedostatečné paměti. Pokud má každá položka cca 7 řádků, tak mohl skončit někde v polovině. Zatím jsem zkoušel maximálně 3000 produktů a tam bohatě stačil limit 128 MB, ale asi by se to dalo nějak optimalizovat...
Mohl bych dostat přístupy a podívat se, co způsobuje konkrétně problémy s pamětí?
Zítra večer Vám pošlu email s přístupy, aby jste mohl otestovat.
Tak jsem to zkoušel a máte pravdu, 128 MB stačí asi na 3000 produktů, takže na 20 tisíc potřebujete paměť skoro 1 GB :-( Zkusím se na to ještě podívat, zda by to nešlo optimalizovat...
Super, díky. Přístup jsem Vám ještě nestihl zřídit, kdyby jste potřeboval jen řekněte. Ale je to ostrý web, proto Vám budu muset udělat i ftp přístup, protože když plugin aktivujete, už se nikam nedostanete.
Ještě mě napadlo, jestli by nebylo lepší tahat to přímo z databáze, než přes api, tím by se asi trošku ušetřilo. A jeden dotaz, kdy se generuje feed heureka a zbozi? Jen při otevření URL, nebo je na to nějaký cron? U pricemanie je to přes schedule, to jsem si všiml, ale u těch předchozích nevím. Pokud se ve stejný čas generuje heureka a zbozi, chce to logicky 2x více paměti. Pokud ne, berte dotaz jako bezpředmětný.
Celá problematika je trochu složitější :-)
Nejdříve jsem XML feedy přidal jen jako klasický RSS zdroj, tedy že se generují pouze ve chvíli, kdy je zobrazena jejich URL adresa. Hlavním důvodem byla okamžitá aktuálnost (ve chvíli zobrazení feedu byl nejaktuálnější stav) a nebylo potřeba řešit ukládání souborů a nastavování cronů.
Pak ale nastal problém s Pricemania, která to neumožňuje a chce klasický soubor (a nikoli průběžně generovaný RSS zdroj). Takže jsem to musel nakonec stejně všechno implementovat :-)
Občas má ale někdo problémy s velikostí feedu a tam není průběžně generovaný RSS zdroj moc vhodný, zejména proto, že to trvá hodně dlouho a např. robot Zboží.cz s tím má problém a když je tam třeba cca 2000 produktů, tak dojde k timeoutu (u Heureky jsem se s tím nesetkal). Takže bude třeba všechny feedy migrovat na klasické generování souborů, které probíhá jednou denně, což je asi dostačující. Problém ale je, že stovky lidí tam už mají doplněnou adresu feedu, který pak přestane fungovat, takže tam musím přidat ještě nějaké automatické přesměrování.
Pro velké eshopy jsem ale implementoval nové řešení, kde je feed zpracováván dávkově. Jednou denně je spuštěn proces cronu pro generování feedu, ale nebude se generovat celý najednou, ale pokaždé bude zpracováno pouze 1000 produktů. Potřeboval jsem to i pro další projekty, takže se to bude hodit :-) U malých eshopů to tedy bude hned, velké eshopy to budou mít generované postupně. Fungovat to bude tak, že se zapíše prvních 1000 produktů do tmp souboru a zároveň se nastaví další cron za 3 minuty, kdy se zapíše dalších 1000 produktů, atd. Jakmile bude hotovo, tak se tmp soubor přejmenuje na feed a smaže se dřívější soubor. V tomto případě by mělo stačit i 64 MB PHP paměti pro desítky tisíc produktů. Už to mám hotové, po otestování to sem pustím. Pokud máte 20 tisíc produktů, tak může generování souboru probíhat poměrně dlouho (teoreticky sice jen 20 x 3 minuty, ale cron je spouštěn pouze při návštěvě nějakého uživatele, takže prakticky to bude spíše několik hodin). Nebo by se mohl zvýšit limit, zatím je odhadem potřeba cca 128 MB paměti na 2500 produktů.
Nějaké nápady, kde by mohl být problém? Než bude feed kompletně vygenerován, tak můe dojít třeba k nějaké změně ceny, ale to by nemělo vadit, protože to pak bude ve feedu druhý den aktualizováno správně. Zatím jediné, co mě napadlo spočívá v tom, že proběhne prvních 1000 produktů a někdo v administraci třeba nějaký produkt smaže či přidá. Potom tam pak ale bude chybět, takže když budeme v druhé dávce pokračovat od produktu č. 1001, tak to může být produkt, který měl dříve pořadí 999 (a už je zahrnut ve feedu), potom někdo přidal (třeba i nějaký importní skript) další novější produkty a nově má pořadí č. 1001 a bude v druhé dávce, takže bude v XML duplicitně. Je to asi náhoda, ale nevím jak porovnávače řeší duplicity?
- [x] Implementovat dávkové zpracování XML feedu Pricemania: https://github.com/pavelevap/ceske-sluzby/commit/3ec79913a98728d262d739c6cb840f2ff9c17138
- [ ] Ošetřit možnost, že dojde během generování feedu ke smazání/přidání nějakých produktů.
- [ ] Zobrazovat aktuální průběh pro kontrolu v administraci (tedy kdy byl/bude skript spuštěn, zda zrovna neprobíhá, přidat tlačítko na okamžité spuštění generování). Jinak bude docházet k problémům, viz např. #73.
- [x] Předělat Zboží a Heureku na stejný systém (Zboží: https://github.com/pavelevap/ceske-sluzby/commit/ec97ce26ef90b2aef409e5261202ddb1d1dd7114, Heureka: https://github.com/pavelevap/ceske-sluzby/commit/d15789db1a11e1594ef946789e1331ba40090e75)
- [x] Negenerovat všechny najednou a umožnit některé odpojit (první část: https://github.com/pavelevap/ceske-sluzby/commit/43d0d6556adbf987b73d3b8aa8325a895e43cb10, druhá část: https://github.com/pavelevap/ceske-sluzby/commit/bdd1966c7ca2b3da961da300e9050b8995d0da7b)
- [ ] Přesměrovat původní RSS zdroje s produkty na nové soubory
- [ ] Limit 1000 produktů nastavit pro všechny obchody nebo brát v potaz memory_limit? #194
- [ ] Pokud dojde k nějaké chybě skriptu, tak zůstává
.lock
option uložena a brání dalšímu generování. - [ ] Doplnit generování i pro Google feed.
- [x] Chtělo by to ale určitě i nějaký jednoduchý testovací feed, kde by bylo třeba jen 10 produktů a zobrazoval se okamžitě.
- [ ] Dále by bylo hezké tlačítko "Aktualizovat feed" pro okamžitou aktualizaci.
- [ ] Možnost nastavení frekvence aktualizace (nyní jednou denně).
Zájemci mohou zkusit otestovat, bez nějakých pozitivních zpětných reakcí to nemůžu pustit ven pro všechny :-)
Dobrý den, na email jsem Vám poslal loginy do eshopu s velkým množstvím produktů. Pořád vykazuje chyby, tak se na to prosím mrkněte. Díky
Zkuste prosím feed pro Zboží v nejnovější verzi, už by to měl také zvládnout (pozor, může to nějakou dobu trvat než se vygeneruje, záleží na počtu produktů). Odkaz na soubor je uveden v administraci (u nastavení XML).
Nainstaloval jsem nejnovější verzi, zítra dám vědět :)
Jedka chybka, v odkazu v administraci je natvrdo uveden wp-content, místo . WP_CONTENT_URL . Včera jsem spustil nyní tam mám feed zbozi-tmp.xml, který je kompletní (166084 řádků :)) zbozi.xml není, možná se nepřejmenoval, nedíval jsem se do kódu, jak to máte provedené. Díky, super práce!
Tak bohužel, do souboru zbozi-tmp.xml se neustále přidává, nyní je v něm feed již 3x a má přes 30MB. Původní měl 10MB.
@novetrendy: Pravda, souvisí to s tím, že se soubor vůbec nepřejmenuje, protože tam je chybná podmínka. Dnes nebo zítra opravím, ale mělo by stačit soubor zbozi-tmp.xml
přejmenovat na zbozi.xml
a dál už to bude bez problémů fungovat a při dalším spuštění se to dá všechno do pořádku. Během testování jsem tam už totiž tento soubor měl, takže jsem chybu neodhalil, ale když ještě neexistuje, tak dochází k problémům...
Super! Díky za odpověď.
@novetrendy: Během několika posledních commitů jsem všechny nahlášené chybky snad opravil, díky za report!
Dobrá práce! Během zítřka otestuji a dám vědět.
@novetrendy: Pozor, nejnovější commit (https://github.com/pavelevap/ceske-sluzby/commit/bdd1966c7ca2b3da961da300e9050b8995d0da7b) umožnil aktivovat pouze generování některých feedů, takže je musíte po aktualizaci ještě v nastavení ručně povolit, jinak se už do budoucna nebudou .xml
soubory pravidelně aktualizovat. Klasických feedů na adrese ?feed=nazev
se to netýká, ty budou fungovat stále. Bohužel to ale jinak udělat nešlo a bylo to potřeba, protože ne všichni používají všechny porovnávače a nechceme zbytečně zatěžovat servery. A stále jsme alpha verze :-)
Asi ještě raději použít content_url()
místo WP_CONTENT_URL
.
Velké množství produktů jsem řešil drobnou úpravou skriptu následovně:
... //foreach loop pro projití produktů
if ($key%25 == 0){ // po 25 produktech se uloží do souboru
file_put_contents($file_name, $xmlWriter->flush(true), FILE_APPEND);
$xmlWriter->flush();
}
}
wp_reset_postdata();
$xmlWriter->endElement();
file_put_contents($file_name, $xmlWriter->flush(true), FILE_APPEND); // přidá zbylé produkty
// nakonec vypíši pouze soubor
header( 'Content-type: text/xml' );
echo file_get_contents($file_name);
Samozřejmě počet produktů, dle kterého se ta iterace provede by bylo hezčí mít jako parametr a mít možnost jej měnit v administraci.
@AlesMenzel: Zajímavé, podobné řešení (rozsekat na více cyklů) jsem také původně zkoušel, ale bohužel mi to s pamětí moc nepomáhalo... Nemohl byste celý skript někam nahrát, abych ho mohl vyzkoušet? Díky!
Pokud dojde k nějaké chybě skriptu (např. https://github.com/pavelevap/ceske-sluzby/commit/62d688b31930d48b12322b02374366c81163699c), tak zůstane .lock
option uložena a brání dalšímu spouštění, asi by to chtělo uživatele nějak upozornit nebo automaticky jednou denně pročistit?
Opravena jedna nepěkná chybka (naštěstí se tam dostala teprve nedávno): https://github.com/pavelevap/ceske-sluzby/commit/3d55f0b0c9f9e3902d44b495cb7a10fb326cc416
Generování do souboru se bude ještě vylepšovat (viz úkoly výše), ale asi až v další verzi.
Tak tohle se myslím docela povedlo :-) Nově je možné jednoduše zkontrolovat zobrazení jednotlivého produktu v konkrétním XML feedu a už není potřeba si stahovat celý feed a pracně ho tam hledat.