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.

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: Reakce na: Non_E

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. :-)
avatar © 2005-2020 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.