Jde cachovat vytváření requestů?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
ZahorskyJan
Člen | 59
+
0
-

Řeším optimalizaci aplikace a blackfire mi jako jedno ze slabých míst ukazuje volání createRequest. Jedná se o eshop, takže odkazů je na stránce dost.

Chtěl jsem výsledek funkce cachovat, takže jsem udělal override ve svém BasePresenteru, ale problém je, že nejsem schopen z parametrů metody ($component, $destination, array $args, $mode) vygenerovat unikátní cache klíč. Když to nechám na Nette\Caching\Cache, tak dostanu pochopitelnou hlášku: Object serialization is not supported protože obecně objekt typu Component nejde „uspat“.

Neřešil to už někdo? Díky za každý nápad nebo zkušenost.

CZechBoY
Člen | 3608
+
+1
-

A jak generuješ ty odkazy? Sama funkce asi nebude úplně nejpomalejší, ale třeba se někde přiojuješ k databázi a taháš odkazy z ní.
Jak vypadá tvoje RouterFactory?

Jan Tvrdík
Nette guru | 2595
+
0
-

@ZahorskyJan Kolik odkazů na stránce vytváříš?

ZahorskyJan
Člen | 59
+
0
-

přikládám ještě blackfire výpisu produktů v kategorii: https://blackfire.io/…d434bb/graph

Když to vezmu podle pořadí % Excl. tak první s čím si myslím, že můžu něco udělat je právě createRequest.

@CZechBoY Nejčastější scénář vytvoření odkazu je, že jedna metoda vytáhne pole produktů, které se má zobrazit. V poli je jejich ID a Slug. Potom vypadá odkaz v latte šabloně takto:

<a href="{link ':Frontend:Catalog:Product:', id=>$item['id'], slug=>$item['slug']}">nazev produktu</a>

Tady je frontend část RouterFactory:

			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/]kosik', array(
				'module' => 'Shopping',
				'presenter' => 'Cart',
				'action' => 'default',
			), $this->httpSecured ? Routers\Route::SECURED : 0);

			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/]vyhledat/[!<search>]', array(
				'module' => 'Catalog',
				'presenter' => 'Category',
				'action' => 'search',
			), $this->httpSecured ? Routers\Route::SECURED : 0);

			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/]texty/[!<slug>]', array(
				'module' => 'Project',
				'presenter' => 'StaticText',
				'action' => 'default',
			), $this->httpSecured ? Routers\Route::SECURED : 0);

			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/][!<id [0-9]+>]-[!<slug>]', array(
				'module' => 'Catalog',
				'presenter' => 'Product',
				'action' => 'default',
			), $this->httpSecured ? Routers\Route::SECURED : 0);

			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/]c-[!<id [0-9]+>]-[!<slug>]', array(
				'module' => 'Catalog',
				'presenter' => 'Category',
				'action' => 'default',
			), $this->httpSecured ? Routers\Route::SECURED : 0);

			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/]chyba', array(
				'module' => 'Project',
				'presenter' => 'Error',
				'action' => 'error404',
			), $this->httpSecured ? Routers\Route::SECURED : 0);

			// general public route
			$public[] = new Routers\Route('[<locale=cs cs|sk|en|de>/][<module>[/<presenter>[/<action>[/<id>]]]]', array(
				'module' => 'Project',
				'presenter' => 'Homepage',
				'action'=> 'default',
			), $this->httpSecured ? Routers\Route::SECURED : 0);
			$router[] = $public;

@JanTvrdík odkazů je na stránce cca 400, v profilování je počet volání createRequest menší protože mám něco cachované na úrovni latte šablony

Jan Tvrdík
Nette guru | 2595
+
+1
-

Nejjednodušší hotfix je něco jako

{capture $linkTemplate}{link ':Frontend:Catalog:Product:', id => 999, slug => abc}{/capture}

{foreach $items as $item}
	<a href="{$linkTemplate|replace:999:$item[id]|replace:abc:$item[slug]}">nazev produktu</a>
{/foreach}
ZahorskyJan
Člen | 59
+
0
-

Jan Tvrdík napsal(a):

Nejjednodušší hotfix je něco jako

{capture $linkTemplate}{link ':Frontend:Catalog:Product:', id => 999, slug => abc}{/capture}

{foreach $items as $item}
	<a href="{$linkTemplate|replace:999:$item[id]|replace:abc:$item[slug]}">nazev produktu</a>
{/foreach}

Díky, zkusím. Přivedlo mě to na myšlenku, že bych ten createRequest zkusil naučit, že některé jednoduché a časté odkazy může brát z cache a zbytek provede standardně. Protože v detailu produktu nejsou žádné persistentní parametry a podobné chytré věci, které to komplikují.

ZahorskyJan
Člen | 59
+
0
-

Tak aktuálně zkouším tento přepis v BasePresenteru a vypadá to, že plní svůj úkol. Ještě dostanu seznam těch adres někam do konfigurace.

V kombinaci s cache v latte pro výpis kategorií, kde bylo taky hodně odkazů, jsem to stáhl o 34%: https://blackfire.io/…7a3c1b/graph

Díky za nakopnutí!

	protected function createRequest($component, $destination, array $args, $mode)
	{
		$allowedDestinations = [
			':Frontend:Catalog:Product:',
			':Frontend:Catalog:Category:',
			':Frontend:Project:Homepage:',
			'toCart!',
		];
		if ( in_array($destination, $allowedDestinations) )
		{
			$cacheKey = [$destination, $args, $mode];
			return $this->cache->load('createRequest/'.md5(serialize($cacheKey)), function(&$dependencies) use ($component, $destination, $args, $mode) {
				$dependencies = [
					\Nette\Caching\Cache::TAGS => [
						'catalog_products/all',
						'catalog_categories/all',
						'system',
					],
				];
				return parent::createRequest($component, $destination, $args, $mode);
			});
		}
		else
		{
			return parent::createRequest($component, $destination, $args, $mode);
		}
	}