Autor | Zpráva | ||
---|---|---|---|
SwimX Profil |
#1 · Zasláno: 22. 1. 2012, 13:26:42
Dobrý den,
řeším na inzertním webu problém, jak upozornit, jednou asi i velké počty lidí, že jejich inzerátu končí platnost. mám skript, který by měl fungovat, ale nefunguje. Pokud jsou pauzy mezi dávkami emailů 0, pak je vše ok, pokud ale zvětšuji pauzy, skript se chová divně. V nastavení, mezi každým emailem 1s a mezi dávkou 180s to skonči na tom, že se mi log soubor vytvoří vícekrát - vždy tolikrát, kolik je dávek, jakoby se skript restartoval..? Poradil by někdo, kde mám chybu? <?php //pocet emailu v davce define ( "SENDBLOCK", 50); //pauza mezi kazdym emailem v sec define ( "EMAILPAUSE", 1 ); //pauza mezi kazdym blokem v sec define ( "BLOCKPAUSE", 180 ); //maximalni doba behu skriptu v sec define('SCRIPT_RUNTIME_LIMIT', 7200); // 2 hod. set_time_limit(SCRIPT_RUNTIME_LIMIT); ignore_user_abort(); // pripraveni emailu z databze do pole $logName = "logs/endingadd-" . date ("Y-m-d-H-i-s") . "-" . mt_rand(0,5000) . ".txt"; $f = fopen ( $logName, "w" ); foreach { $mail = new phpmailer() ; // nejake texty emailu, atd. if ( $mail -> Send() ) { fwrite( $f, "OK" ); $allOk ++; } else { fwrite( $f, "FAILED" ); $allFailed ++; } $sendDone ++; if ( $sendDone % SENDBLOCK == 0 ) { $sendDone = 0; fwrite( $f, " * - sleep " . BLOCKPAUSE . "s at " . date ( "d.m.Y (H:i:s)" ) . "\r\n"); sleep ( BLOCKPAUSE ); } sleep ( EMAILPAUSE ); } |
||
Časová prodleva: 3 dny
|
|||
Alphard Profil |
#2 · Zasláno: 25. 1. 2012, 10:19:26
Ten script se spouští ručně, není možné, že ho třeba prohlížeč zavolá vícekrát když čeká odpověď? Já jsem u podobných systémů využíval cron, tj. žádná BLOCKPAUSE, jen EMAILPAUSE, kde je 1 s po každém mailu možná zbytečný luxus. Odešle se dávka a script se ukončí. PHP není stavěné na dlouhoběžící scripty.
|
||
SwimX Profil |
#3 · Zasláno: 25. 1. 2012, 16:01:08
Alphard:
teď ho kvůli testování spouštím ručně, potom tam bude nastaven cron. ten restart skriptu zřejmě měl opravdu za vinu prohlížeč, ale stále to skončí na tom, že se po jedné dávce skript uspí – pokud to je na 10s tak je to ok, pokud je to na víc tak už se neprobudí. Přitom u set_time_limit v manuálu píší, že nefunguje jen při zaplém safe_mode což podle http://www.hotelpersonal.cz/info.php nemáme. |
||
Alphard Profil |
#4 · Zasláno: 25. 1. 2012, 16:25:04
Nevím, s tím nemám moc zkušeností. Nejdéle držím script při životě tak 15 minut, 2 hodiny jsem nezkoušel. Cron není problém volat po minutě, takže bych to celé navrhoval jinak, jak jsem psal [#2].
|
||
David P Profil * |
#5 · Zasláno: 25. 1. 2012, 17:10:01
Jednou mi script běžel 12 hodin také pomocí sleep, takže technicky to možné je
|
||
Keeehi Profil |
#6 · Zasláno: 25. 1. 2012, 18:17:48
Alphard:
„PHP není stavěné na dlouhoběžící scripty.“ Nějaký důvod? |
||
Alphard Profil |
Keeehi:
„Nějaký důvod?“ Obecně nemám konkrétní důvod, neznám detailně vnitřní kódy Apache + PHP, takže nemohu posoudit kvalitu garbage collectoru, memory leaků, schopnosti optimálně držet dlouho trvající procesy, vytížení při uspání. Byl tady pokus o PHP GTK, ale moc se to neujalo, nevím co bylo příčinou. Osobně bych na dlouhoběžící programy vybral jiné jazyky. Jako možný problém mi např. připadá velmi problematické ukončení scriptu při chybě (která dělá něco nevhodného a sama neukončí běh, např. tento script by začal kvůli neintegrity databáze neřízeně spamovat a nešlo by ho zastavit), asi jediná možnost psát na podporu (pokud to není náš server). Tady konkrétně s tím byl problém, doporučil jsem řešení, které mi dobře funguje a odpovídá obvyklé praxi dlouho neběžícího PHP scriptu. Svůj návrh jsem napsal až po 3 dnech neaktivity, jestli vám někomu dobře funguje něco jiného, mohli jste dávno uvést své řešení. Svůj výrok přeformuluji, omlouvám se, že si nehlídám každou větu. |
||
Keeehi Profil |
#8 · Zasláno: 25. 1. 2012, 20:30:15
Alphard:
„Svůj výrok přeformuluji, omlouvám se, že si nehlídám každou větu.“ Mrzí mě, že jsi to vzal takto. Mě opravu zajímá, jestli jsou s dlouhoběžícími scripty problémy. Vím, že třeba u DVBgrabu jsou 2 nekonečné scripty a nevím o žádných problémech. Doma mi taky nějaké nekonečné smyčky běží a nezaznamenal jsem žádný problém. Takže by mě zajímalo, jestli mám očekávat nějaké problémy. |
||
Alphard Profil |
#9 · Zasláno: 25. 1. 2012, 20:58:16
[#8] Keeehi
O nic nejde, já se obecně snažím psát přesně a neuvádět nějaké mýty. Tady jsem napsal věc, která je nepodložená, byla to chyba. To ale samozřejmě nebrání diskusi o vhodnosti dlouhoběžících skriptů. Snad to nebude SwimXovi vadit, kdyžtak to vyčlením. Já právě raději vícekrát spouštím stránku s kratším max_execution_time, než dělat nekonečné scripty. Doma mi cron nahrazuje funkce Opery Reload Every někaký čas. U rozesílání mailů mám script kombinový s databází, kde vždy vytáhnu určitou dávku mailů $queue = $this->newsletterM->getQueue(); $queue->where('((n.last_send < date_sub(now(), interval 20 hour) or n.last_send is null))'); $queue->limit(30); foreach ($queue as $item) { $this->sendMail($item); } Cron je spouštěn v určitých hodinách po 5 minutách, to omezení 20 hodin brání opakovanému odeslání. |
||
Keeehi Profil |
#10 · Zasláno: 25. 1. 2012, 23:02:03
Alphard:
Pokud jsem dělal někde nějakou jednorázovou akci, kde jsem potřeboval "cron" tak jsem také používal tu operu nebo <meta http-equiv="refresh" content="xxx"> . Ovšem pokud to chci mít nezávislé na prohlížeči tak musím použít cron nebo nějakou smyčku.
Teď třeba chci kontaktovat nějaký server každých 5 sekund. Tak místo cronu používám: while(1){ ... sleep(5); } |
||
SwimX Profil |
#11 · Zasláno: 25. 1. 2012, 23:20:14
Alphard:
„Snad to nebude SwimXovi vadit, kdyžtak to vyčlením.“ rád se poučím, netřeba to vyčleňovat. Keeehi: a mohl bys poradit, proč můj nekonečný skript nechce být nekonečný? |
||
Keeehi Profil |
#12 · Zasláno: 25. 1. 2012, 23:44:44
Už to možná vidím: řádek 19, máte špatně ten foreach. Není tam napsáno co procházet a do jaké proměnné to vkládat.
|
||
SwimX Profil |
#13 · Zasláno: 26. 1. 2012, 00:47:55
Keeehi:
bohužel, to je jen ilustrační kód, pokud zmenším pauzy - funguje vše ok. Jakoby nefungovalo to set_time_limit, přitom podle php manuálu fungovat nemá jen při zaplém safe_mode a to na serveru nemáme (viz php info někde výše v komentu). udělat to tak, jak říká Alphard by sice bylo pěkné, ale moc se mi do toho nechce, je to další zápisy do DB kdy se co poslalo. takle se jednou za 24 hodin spustí cron - a pošle se spousta emailů.. |
||
Alphard Profil |
SwimX:
„Jakoby nefungovalo to set_time_limit“ Vypisuje se vám nějaká chyba? Nebo ukončujete spojení? Je něco v logu? Jestli máte povolené ini_set(), zkuste to přímo. Můžete zkusit set_time_limit(7200); while (true) { file_put_contents('log.txt', date('c').PHP_EOL, FILE_APPEND); sleep(5); } „ale moc se mi do toho nechce, je to další zápisy do DB kdy se co poslalo“ Nevím, kde berete adresy, ale jestli je máte v db jako samostatné záznamy, tak to lze řešit i jedním update where id in(...) na závěr, to server přežije.
|
||
Keeehi Profil |
Z manuálu PHP
"The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real." Pokud tedy nejedete na windows, čas v set_time_limit() by na to neměl mít vliv. Problémové místo by šlo identifikovat třeba takto: Na několik míst vložit file_put_contents("log.txt", "Misto: xxx\n", FILE_APPEND); |
||
SwimX Profil |
#16 · Zasláno: 26. 1. 2012, 01:19:49
Alphard:
„Nevím, kde berete adresy, ale jestli je máte v db jako samostatné záznamy, tak to lze řešit i jedním update where id in(...) na závěr, to server přežije.“ Nejde o zátěž serveru, ten toho vydrží hodně a adresy sou z DB. Nechce se mi to psát, sem od přírody líný člověk :-)) „Vypisuje se vám nějaká chyba? Nebo ukončujete spojení? Je něco v logu? Jestli máte povolené ini_set(), zkuste to přímo.“ Nevypisuje se nic. Spustím skript - zavřu okno prohlížeče. 30s to jede na pozadí, do logu to píše email odeslán, email mi přijde. Po 50ti emailech se to uspí na 40s (např, mezi dávkami) a už se to neprobudí, v logu je sleep at TIME Keeehi: problémové místo je jednoduché - #36 sleep ( BLOCKPAUSE ); a pak už nic :-) Zkusím si zítra víc pohrát, nastavit to jinak, než pomocí set_time_limit. ini_set by jít měl. Zatím mnohokrát děkuji, zítra napíšu. |
||
Keeehi Profil |
#17 · Zasláno: 26. 1. 2012, 01:49:28
SwimX:
Zkoušíte to doma nebo někde na hostigu. |
||
SwimX Profil |
#18 · Zasláno: 26. 1. 2012, 12:11:06
Keeehi:
na serveru, www.hotelpersonal.cz/info.php doma nemám rozchozené smtp. |
||
Keeehi Profil |
#19 · Zasláno: 26. 1. 2012, 12:46:41
Zkoušel jste dlouhý sleep nahradit několika krátkými?
if ( $sendDone % SENDBLOCK == 0 ) { $sendDone = 0; fwrite( $f, " * - sleep " . BLOCKPAUSE . "s at " . date ( "d.m.Y (H:i:s)" ) . "\r\n"); for ($i=0; $i<BLOCKPAUSE; ++$i) { sleep ( 1 ); } } |
||
Davex Profil |
#20 · Zasláno: 26. 1. 2012, 12:57:44
SwimX:
Možná by mohlo pomoci zvýšit v konfiguraci hodnotu max_execution_time .
|
||
Keeehi Profil |
#21 · Zasláno: 26. 1. 2012, 13:00:47
Jelikož je server na Linuxu, tak doba strávená v sleep by se do max_execution_time ani do time_limit započítávat neměla -> mělo by být jedno jaké číslo je v sleep nastaveno.
|
||
SwimX Profil |
Alphard:
„Jestli máte povolené ini_set(), zkuste to přímo.“ nepomohlo, skript se uspí na 60s pak druhá dávka, dalších 60s a pak se neprobral Keeehi: „Zkoušel jste dlouhý sleep nahradit několika krátkými?“ nepomohlo, logy se tváří v obou případech stejně nyní jsem spustil: [#14] Alphard skript až skončí, postnu log poprvé jsem Alphardův skriptík spustil omylem nevím kolikrát (z prohlížeče). Tento skript už běží 25 minut a stále zapisuje do souboru. Potom jsem udělal kopii a spustil ho právě jednou. Log je zde: http://hotelpersonal.cz/admin/cron/log2.txt běžel 1 minutu 40s pokud dobře počítám. Spustil jsem tedy 3 kopii opět právě jednou. viz http://hotelpersonal.cz/admin/cron/log3.txt běžela uplně stejně dlouho. Teď nechápu, proč tedy http://hotelpersonal.cz/admin/cron/log.txt stále narůstá? kód testu <?php ignore_user_abort(); set_time_limit(7200); while (true) { file_put_contents('log.txt', date('c').PHP_EOL, FILE_APPEND); sleep(5); } ?> tak ještě jeden test: http://hotelpersonal.cz/admin/cron/log5.txt byl spuštěn 5x. Ve skriptu se nechá vypozorovat, že v jeden zápis zača v 2012-01-29T00:41:25+01:00 a ten zřejmě skončil 2012-01-29T00:43:05+01:00 přesně po minutě a 40s další začal v 2012-01-29T00:41:45+01:00 a skončil v 2012-01-29T00:43:25+01:00 taktéž minuta 40. a ty další tři budou jistě podobné. tento log nenarůstá. Dokáže někde poradit? :-) |
||
Davex Profil |
#23 · Zasláno: 29. 1. 2012, 13:11:11
Podobný skript mi tu běžel několik hodin. Zkus si zapnout chybový log PHP, zda se v něm náhodou něco neobjeví.
.htaccess: <IfModule mod_php5.c> php_flag log_errors On php_value error_log php_errors.log </IfModule> |
||
SwimX Profil |
#24 · Zasláno: 30. 1. 2012, 13:22:53
Davex:
nic to nevypsalo. Skript běžel svých 100s. |
||
Davex Profil |
#25 · Zasláno: 30. 1. 2012, 20:10:41
SwimX:
Tak bych se na to zkusil zeptat technické podpory hostingu. Třeba skripty běžící na pozadí takto omezují. |
||
Časová prodleva: 11 let
|
0