2010-04-14 8 views
14

Wie löst man set_time_limit, das PHP-CLI nicht beeinflusst?set_time_limit beeinflusst nicht PHP-CLI

#!/usr/bin/php -q 
<?php 
set_time_limit(2); 
sleep(5); // actually, exec() call that takes > 2 seconds 
echo "it didn't work again"; 
+0

Wie Pascal MARTIN weist darauf hin, set_time_limit ist nicht der richtige Ansatz. Ich brauche irgendwie, um dieses Skript nach Sekunden zu töten. – Devrim

+1

das gleiche Problem, zusätzliche Prämie, brauchen eine Möglichkeit, den Prozess CLI-Prozess von Cron nach 5 Minuten – Moak

+0

zu stoppen stoppen Nur um die Kopfgelder zu klären geht nicht zu Pascal MARTIN, da seine Antwort nicht funktioniert für PHP-CLI – Moak

Antwort

9

Die Lösung hier ist pcntl_fork() zu verwenden. Ich fürchte, es ist nur POSIX. PHP muss mit --enable-pcntl und nicht --disable-posix kompiliert werden. Der Code soll wie folgt aussehen:

<?php 

function done($signo) 
{ 
    // You can do any on-success clean-up here. 
    die('Success!'); 
} 

$pid = pcntl_fork(); 
if (-1 == $pid) { 
    die('Failed! Unable to fork.'); 
} elseif ($pid > 0) { 
    pcntl_signal(SIGALRM, 'done'); 
    sleep($timeout); 
    posix_kill($pid, SIGKILL); 
    // You can do any on-failure clean-up here. 
    die('Failed! Process timed out and was killed.'); 
} else { 
    // You can perform whatever time-limited operation you want here. 
    exec($cmd); 
    posix_kill(posix_getppid(), SIGALRM); 
} 

?> 

Im Grunde, was das bedeutet ist Gabel ein neues Verfahren, das läuft den else { ... } Block. Bei der (erfolgreichen) Schlussfolgerung senden wir einen Alarm zurück an den Elternprozess, der den elseif ($pid > 0) { ... } Block ausführt. Dieser Block hat einen registrierten Signalhandler für das Alarmsignal (done() Rückruf), der erfolgreich beendet wird. Bis das empfangen wird, schläft der Elternprozess. Wenn die Zeitüberschreitung sleep() abgeschlossen ist, sendet es eine SIGKILL an den (vermutlich hängen) untergeordneten Prozess.

+0

+1, eine sehr vernünftige Antwort – Brad

15

max_execution_time Die Grenze, die, was set_time_limit Mengen ist, zählt (zumindest auf Linux) die Zeit, die durch den PHP-Prozess ausgegeben wird, während der Arbeit.

der Bedienungsanleitung Seite von set_time_limit() Zitiert:

Hinweis: Die set_time_limit() Funktion und die Konfiguration Richtlinie max_execution_timenur beeinflussen die Ausführungszeit des Skript selbst.
Jedes Mal auf Aktivität ausgegeben, die außerhalb der Ausführung des Skripts wie System geschehen system() Anrufe verwenden, Strom Operationen, Datenbankabfragen, etc. nicht enthalten, wenn die maximale Zeit bestimmt wird, dass das Skript Laufen gewesen .
Dies gilt nicht für Windows, wo die gemessene Zeit real ist.

Wenn Sie sleep() verwenden, Ihre PHP-Skript nicht funktioniert: Es ist nur darauf warten, ... So sind die 5 Sekunden warten auf Sie werden berücksichtigt, indem die max_execution_time Grenze nicht genommen.

+0

danke für die Antwort, aber ich habe immer noch das Problem zu lösen, gibt es sowieso, dass ich dies mit einem anderen Ansatz tun kann? – Devrim

+1

Nun, ich würde sagen, sollte nicht 'sleep()', wenn Sie nicht wollen, dass das Skript für mehr Zeit am Leben bleibt als nötig ;-) ;;; genauer gesagt, 'max_execution_time' ist als Sicherheitsvorkehrung gegen Skripte gedacht, die zu viel Ressourcen benötigen, und nicht als irgendeine Art von präzisem Timing-Mechanismus. –

+0

dort ist eine exec() ausgeführt anstelle von sleep() dort. und einige exec() Sachen hängen unbegrenzt. Ich suche auch, um es innerhalb von exec (auf Linux-Shell), wie exec (kill_after15secs myscript.sh) zu töten, aber ich kann nicht scheinen, dass auch nicht ... – Devrim

4

Sehr hackish, aber da ich CLI-Skripte viel verwenden, gebe ich schändlich auf, einen ähnlichen Hack in der Vergangenheit geschlagen zu haben. 2 Skripte benötigt.

Ihr erstes Cron-Skript (das hängt) protokolliert seine Startzeit und Prozess-ID in einer flachen Datei -> die Funktion getmypid wird dafür Ihr Freund sein. Ein zweites Skript, das von cron alle (x) Minuten ausgeführt wird, überprüft die Flatdatei, tötet alles, was die zugewiesene Ausführungszeit überschritten hat, löscht die Flatdatei und meldet sogar eine andere Datei an, wenn Sie möchten.

Viel Glück;)

UPDATE:

diese Frage Remembered und kam zurück zu posten. Beim Durchstöbern von Sebastian Bergmanns GitHub-Account bin ich auf php-invoker gestolpert. In den Worten des Autors:

Utility-Klasse zum Aufrufen PHP Callables mit einem Timeout.

Obwohl die aktuelle Antwort auf Linux-Basis nicht den mobilen Einsatz ist sehr gut, wenn Cross-Plattform-Lösung Diese Lösung benötigt wird, sollten Windows-kompatibel, für die armen Seelen auf windoze läuft. Herr Bergmann ist ein PHP-Gott, ich garantiere absolut die Qualität des Skripts.

+0

Sie würden irgendeine Art von Cron-Jobs-Manager brauchen, um Prozesse automatisch zu starten/zu loggen/anzuhalten, aber es würde gut funktionieren – Quamis

5

Könnten Sie versuchen, Ihr PHP über Exec auszuführen und den "Timeout" -Befehl verwenden? (http: //packages.ubuntu.com/lucid/timeout)

verwendung: timeout [-signal] zeitbefehl.

+1

Super einfach, funktioniert genau wie erwartet zB ' timeout 5m/usr/bin/php/var/www/beispiel/cron.php' – Moak

4

Ich bin davon überzeugt, dass das Skript in einer Schleife irgendwo hängt. Warum nicht einfach eine $STARTUP_TIME=time() das Skript starten, und dann in der Schleife einchecken, wenn das Skript beendet werden muss?

+0

+1 es ist nur normale Art. Ich verstehe nicht, warum es nicht verwendet wurde und nicht früh vorgeschlagen wurde. –

+0

@ OZ: Wenn das Skript * einen Prozess ausführt, blockiert es - warten Sie, bis der Kindprozess beendet ist, bevor Sie mit der nächsten Anweisung im Skript fortfahren. Wenn der ausgeführte Prozess die Kontrolle sofort an das Skript zurückgibt (z. B. durch mit dem bash '&' -Operator funktioniert diese Logik –

2

EDIT 1

bemerkte ich diesen Kommentar in PHP-Handbuch:

Bitte beachten Sie, dass unter Linux wird Schlafzeit ignoriert, aber unter Windows zählt als Ausführungszeit.

Soweit ich verstehe, wird Schlaf als Systemaufruf implementiert und daher von PHP as described in the manual ignoriert.

EDIT 2

gibt es eine exec() dort anstelle von sleep() ausgeführt wird. und einige exec() stuff hängt auf unbestimmte Zeit. ich bin auch für die Suche von innen exec (auf Linux-Shell), wie exec (kill_after15secs myscript.sh), töten, aber ich kann nicht scheinen zu finden, dass entweder

Ich sehe jetzt die eigentliche Frage. Unter der Annahme, dass Sie in einem Lunix/Unix-Umgebung arbeiten, können Sie eine Lösung um diese Linien entwickeln:

<?php $pid = system('sh test.sh >test-out.txt 2>&1 & echo $!'); ?> 

Ratet mal, was dies die Prozess-ID des Prozesses gefangen Sie begonnen haben. Sie können es zusammen mit dem Zeitstempel in einer Datenbank oder Textdatei speichern. In einem anderen cron-Skript, das, sagen wir, alle 5 Minuten ausgeführt wird, abgerufen werden alle Prozess-IDs, die vor 5 Minuten erstellt wurden, und überprüfen, ob sie noch laufen:

<?php $status = system('ps ' . $pid); ?> 

Wenn Prozess noch läuft, erhalten Sie zwei Zeilen der Ausgabe :

PID TTY STAT TIME COMMAND 
2044 ? S 0:29 sh test.sh 

Wenn ja, es so enden:

<?php system('kill ' . $pid); ?> 

ich schrieb einen Artikel über creating background processes in PHP (sie und jagen hinterher). Alle Beispiele wurden von dort kopiert.

EDIT 3

Alle miteinander verbunden Punkte:

<?php 
    $pid = system('sh test.sh >test-out.txt 2>&1 & echo $!'); 
    $timer = 300; 
    while(--$timer) { 
     sleep(1); 
     $status = system('ps ' . $pid); 
     $status = explode("\n", $status, 2); // I am not sure, please experiment a bit here 
     if (count($status) == 1 || trim($status[ 1 ]) == '') { 
      die('spawned process ended successfully'); 
     } 
    } 
    system('kill ' . $pid); 
    die('spawned process was terminated'); 
?> 
Verwandte Themen