Požadavek nečekající na odpověď

Školení, která pořádám

Pokud má být výsledkem požadavku na webový server spuštění nějaké dlouhotrvající operace, je vhodné alespoň rychle zobrazit nějakou hlášku, která o tom uživatele informuje. Jedno možné řešení spočívá ve vysypání výstupu s hláškou a pokud navíc potřebujeme, aby operace doběhla i v případě přerušení stahování stránky, tak jeho zabránění. Nevýhodou tohoto řešení je po celou dobu zobrazený ukazatel stahování stránky, který může některé uživatele iritovat.

Pokud by se jednalo o program příkazové řádky, nabízí se jeho spuštění s operátorem &, který zajistí provedení na pozadí. PHP tento operátor podporuje při současném přesměrování výstupu např. do /dev/null ale nepodporuje.

Ideálním řešením by bylo napsat si démona, který poběží stále a jen bude čekat na požadavky např. na socketu. To je ale poměrně pracné a navíc na většině webhostingů nerealizovatelné.

Dominik Fišer mě upozornil ještě na jedno možné řešení – dlouhotrvající operaci je možné napsat do samostatného skriptu, ten nechat spustit funkcí curl_multi_exec a nečekat na odpověď. Jednoduché, elegantní.

Jakub Vrána, Řešení problému, 2.7.2008, diskuse: 8 (nové: 0)

Diskuse

Non_E:

PHP samozřejmě podporuje spouštění shellových příkazů na pozadí klasicky ampersandem. V zaměstnání to tak děláme běžně. Jen je potřeba ošetřit stdout a stderr.

Viz http://cz2.php.net/manual/en/function.exec.php
Note: If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends.

ikona Jakub Vrána OpenID:

Díky za upozornění, opravil jsem to.

Salko:

Ja osobne už nejaké 4 roky používam metódu, že pomocou fsockopen() otvorím port 80 (alebo nastavený port), vygenerujem normálnu HTTP požiadavku (GET alebo POST) a zatvorím spojenie, bez toho aby som čakal na odpoveď. V tejto požiadavke zavolám servisný PHP skript, ktorý ako prvý riadok ma funkciu ignore_user_abort(true);
Neviem či je to úplne podľa pravidiel, ale za ten čas som nemal žiaden problém a môžem vykonávať pomocné servisné skripty ktoré nijako nezdržujú užívateľov...

Prog.:

Myslím, že práve na takéto prasačinky sa hodí trocha ajaxu. Spojenie so serverom sa tak ani nemusí uzatvárať - môže byť celý čas aktívne a môžu sa po ňom priebežne zo servera posielať údaje o stave operácie...

Dundee:

Díky za zajímavý článek. O funkci ignore_user_abort slyším poprvé.

optik:

na dlouhotrvající věci nedoporučuji používat ani curl a ani cokoli jiné, kde na druhé straně bude váš apache, protože pokud máte vytížený server, tak ten dlouhotrvající proces se lehce může stát tím, který už bude navíc a zablokuje vám provoz ostatních normálních requestů. Lepší je rozhodně ten démon a netřeba vůbec psát vlastního, inetd bohatě postačí, pak jen to trochu zabezpečit a hotovo.

Elixon:

Jen tak pro akademicke (tedy ne prilis prakticke ;-) doplneni k tematu: technologie s nazvem "Web server push":

https://bugzilla.mozilla.org/show_bug.cgi?id=237319

Andrew:

Pro nečekání na odpověď jsem dlouho s úspěchem používal curl_multi_exec. Nyní jsem přešel na nový server (nginx, curl 7.24 a PHP 5.5) a tento trik přestal fungovat. Čeká mě tedy zkoumání, co na to má vliv, ale pokud máte někdo nějaký tip, budu rád. :-)

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.