Kako pognati PHP skripto "v ozadju"?
6 naročnikov
6 naročnikov
Lep pozdrav vsem skupaj!
Kako ste kaj? Jaz popizdevam nad Linuxom ... :)
Naj opišem situacijo. Recimo, da imam PHP skripto "parent.php" in skripto "child.php". Skripta "child.php" se izvaja 10 minut.
V skripti "parent.php" imam nekaj kode, nato SPROŽIM skripto "child.php", ki naj se v miru izvaja, skripta "parent.php" pa TAKOJ nadaljuje z delom in NE čaka na output skripte "child.php".
V praksi to pomeni, da se skripta "parent.php" izvaja pol sekunde in v tem času pokliče skripto "child.php". Skripta "child.php" pa se potem izvaja svojih 10 minut in opravi vse težaško delo.
A je do tukaj še vse jasno? :)
No, trik je v tem, da sem poskusil že miljon enih opcij.
1.) V skripti "parent.php" sem klical skripto "child.php" z ukazom exec("/usr/bin/php /home/nekuser/nekamapa/child.php >/dev/null 2>&1");. To NI bilo uspešno, "parent.php" je čakal na output in se izvajal 10 minut.
2.) Potem sem poskusil z exec("/usr/bin/php /home/nekuser/nekamapa/child.php&");, ki naj bi skripto pognal v backgroundu. Žal je zgodba povsem enaka.
3.) Nato sem poskusil z pclose(popen("/usr/bin/php /home/nekuser/nekamapa/child.php&", "r"));. Srce je za trenutek vztrepetalo! Stvar dela! Well, not really.
V tem primeru stvar res dela, če "parent.php" poženem iz konzole (SSH - PuTTY), in to povsem pravilno! Če pa jo poženem z obiskom te skripte prek URLja z brskalnikom, pa spet NE dela in se "child.php" sploh ne izvede. V tem primeru se sicer "parent.php" res izvede v sekundi, ampak se "child.php" sploh NE pokliče.
Ima mogoče kdo kakšno idejo, kako bi lahko rešil ta problem? Povsod po netu najdem predloge, da bi stvar z ">/dev/null 2>&1" morala delovati. Ampak na mojem serverju žal ne. Wtf.
Uporabljam ServInt VPS za $89 mesečno. Njihov support je brez moči.
Please help meh. !!! 11 stofakingenajsttisoč !
Anže
14 odgovorov
Mogoč kej takega:
http://blog.a2o.si/2009/08/18/standalone-preforking-php-application-server-framework/
Vsekakor pa poglej še php fork:
http://www.google.si/search?client=firefox-a&rls=org.mozilla%3Aen-GB%3Aofficial&channel=s&hl=sl&source=hp&q=php+fork&meta=&btnG=Iskanje+Google
Crontab uporabi za tole da ti parent laufa v ozadju. Drugače ne bo šlo oz. se boš zapletel. Seveda preden se parent spet izvede, preveri da mogoče že ne teče... kreiraj kak "pid" fajl, in če je ta kreiran, se parent ne izvede, ker že teče... kar se tiče php forka... ti ga odsvetujem, ker je generalno precej neuporaben, prav tako pa ga večina hostingov niti ne podpira. (Razen seveda če imaš svoj strežnik za tole, potem si ga usposobi in potestiraj če to reši tvoje težave) Drugače moraš pa vedeti da multithreadinga php ne podpira, kar bi ti rad, se mi zdi... Če ima kaj veze z leechanjem URL-jev skripta, potem si poglej cURL, ta ima podporo za multithreading v phpju.
Hvala obema.
Najprej si bom pogledal tisto "standalone preforking whatever", ker glede na izid pri točki 3.) zna biti nekaj narobe s pravicami, in bom poskusil pred klicem te funkcije userja "su"jat kam drugam.
Blackbird, cronjob bi prišel v poštev, ampak ni tko "by the book" rešitev ... predvsem pa potrebujem to, da se "parent.php" res čim hitreje izvede in pokliče "child.php", namesto da cronjob recimo vsake 3 sekunde obremenjuje bazo in gleda, če ga čaka kaj dela.
Imam svoj VPS, ja, tako da bi se načeloma dalo nakonfigurirat vse - če bi znal. Saj pravim, fantje po internetu pravijo, da njim varianta z ">/dev/null 2>&1" deluje, meni pa noče delovat.
Ne gre pa za nobeno leechanje, ampak dejansko za en poskus multithreadinga v PHP, ja. Vem, da PHP nativno multithreadinga ne podpira, hehe - če bi ga, vas ne bi js moril s takimi bednimi težavami.
Ampak v tem specifičnem primeru multithreading nujno potrebujem, in izvest ga moram praktično točno na opisan način.
Tako da, js grem zdele še eni 2 zadevi probat ... če pa ima kdo še kakšno idejo, pa pliz povejte! :)
Anže
Kljub odsvetovanju ti priporočam tudi php fork, sej ti vzame 1 urco, da naštudiraš osnovni proces in vidiš, če ti reši problem. Tudi classe (wrapper) okrog tega se da dobiti.
Kaj pa tako ?
exec("/usr/bin/lynx -dump http://www.domena.com/neka_mapa/child.php >/dev/null 2>&1");
Hm, zdaj sem prišel do tega, da v skripto parent.php vtaknem malo drugače formuliran ukaz, in sicer takole:
exec("/usr/bin/php /home/nekuser/nekamapa/child.php > /dev/null &");
Če sedaj parent.php poženeš prek command line, vse deluje pravilno.
Če pa parent.php poženem preko browserja, se pa zgodi nekaj nadvse čudnega. Stvar ne javi nobene napake, kljub errorreporting(EALL|ESTRICT) in iniset("display_errors", 1), ampak se povsem obesi.
Browser kaže, da se skripta nalaga v nedogled. Če to nalaganje prekinem, ne morem več z browserjem odpret ničesar več na isti domeni, vse se v nedogled nalaga. Če browser zaprem in spet zaženem, potem lahko spet odpiram strani na tej domeni.
Torej, ko parent.php poženem preko browserja, se ta exec() ukaz nekako povsem obesi in se ne odziva več ... Res ne morem ugotovit, v čem je problem.
Anyone???
Zakaj se ti brskalnik ne odziva več je zaradi keep-alive direktive.
Kaj se pa dogaja s procesom pa testiraj tako, da sproti ispisuješ echo '1' ter ob_flush() (al sent), tako boš videl kje se stvari obesi. Za vsakim echo '1'; naredi še exit(); da boš vedel do kje uspešno prideš in kje no. Basic debugging.
Uh, fantje, po cirka 10 vloženih urah stvar dela.
Na koncu sem opustil vsako PHP "forkanje", ker hudiča preprosto nisem mogel pripravit do delovanja, poskusil sem vsaj 10 variant. Potem pa sem našel rešitev v telih par vrsticah kode:
$query = "GET " . $script_url . " HTTP/1.0\r\n";
$server = substr(strreplace("http://", "", $scripturl), 0, strpos(strreplace("http://", "", $scripturl), "/"));
if (!$fsock[$fsockcounter] = fsockopen($server, 80)) {
throw new Exception("Unable to open socket connection for script {$scripturl}, server: {$server}");
}
fputs($fsock[$fsockcounter], $query);
fputs($fsock[$fsockcounter], "Host: {$server}\r\n");
fputs($fsock[$fsock_counter], "\r\n");
streamsetblocking($fsock[$fsockcounter], 0);
streamsettimeout($fsock[$fsockcounter], $this->timeout);
Na ta način server požene skripto prek URLja in takoj pozabi nanjo. Minus je predvsem to, da mora biti ta skripta "navzven odprta", torej dostopna preko URLja. Plus je pa to, hm, da zadeva faking dela.
:)))
Zares najlepša hvala vsem še enkrat, vidim, da vas je dosti pravih maherjev tuki gor!
Anže :)
dunker:
Uh, fantje, po cirka 10 vloženih urah stvar dela.Na koncu sem opustil vsako PHP "forkanje", ker hudiča preprosto nisem mogel pripravit do delovanja, poskusil sem vsaj 10 variant. Potem pa sem našel rešitev v telih par vrsticah kode:
......
:)))Zares najlepša hvala vsem še enkrat, vidim, da vas je dosti pravih maherjev tuki gor!
Anže :)
Hvala tebi za tole. Bom tudi jaz to rabil čez kake 2-3 mesce.
LP