Manchmal, aber nur manchmal ….
Im Leben eines PHP Entwicklers kommt man häufig an den Punkt, dass man eine Aktion in regulären Abständen ausführen muss. Sei es das Aufräumen der Datenbank per Skript oder das leeren eines bestimmten Verzeichnisses. Jedem von euch werden hier bestimmt noch einige Beispiele einfallen. Der Königsweg dies zu lösen ist natürlich ein Cronjob, den man einrichtet und der bestimmte Skripte zu einer bestimmten Uhrzeit ausführt. Was aber tun, wenn keine Cronjobs zur Verfügung hat, da man nur einen „normalen“ Webspace besitzt. Ja es soll Leute geben, die keinen eigenen Server besitzen.
Nehmen wir also an, wir wollen bei jedem tausendsten Aufruf einer Webseite etwas spezielles tun. Jetzt können wir uns einfach einen Counter definieren, den wir in der Datenbank speichern und bei jedem Aufruf der Seite um Eins nach oben zählen. Dies wären zwei Datenbankzugriffe pro Seitenaufruf. Einer zum Lesen und einer zum Schreiben. Klingt relativ viel, dafür dass wir einfach nur eine Zahl hochzählen wollen.
Wenn man genau bei jedem 1.000sten Mal die Aktion ausführen muss, dann wird einem nichts anderes übrig bleiben, aber in den meisten Fällen genügt es auch, dass es ungefähr 1000 Aufrufe sind. Ob es jetzt 950 oder 1050 sind spielt meistens keine Rolle. Wenn dies so ist, dann sollte man einfach eine Zufallszahl zu Rate ziehen.
if ( rand(1,1000) == 500 ) { doAction( ); }
Dieser Code verschwendet keine Datenbankzugriffe und liegt auch so ganz gut in Performance Dingen. Problem also gelöst. Das geht natürlich nur wenn der verwendete Zufallsgenerator auch gut ist und gleichmäßig seine Zahlen verteilt, aber davon gehen wir hier mal aus.
Witzig. So hab ich das noch gar nicht in Erwägung gezogen. Da sieht man mal wie die Denkstrukturen schon eingefahren sind 🙂
Warum nicht die allseits bekannten „Inline-Cronjobs“? In der Datenbank wird dazu ganz normal (wie auch in einer CronTab) gespeichert, wann ein Job ausgeführt werden soll.
Mit einem Seitenaufruf wird geprüft, ob irgendwelche Jobs jetzt starten müssten oder schon vor x-minuten/stunden usw. hätten starten müssen (es aber noch nicht getan haben, weil seit dem z.B. noch kein Seitenzugriff erfolgte), die Jobs werden dann angeschmissen und es wird noch vermerkt, wann dieser Job zuletzt lief.
Klar, ist es etwas mehr Overhead als in der Count-Lösung, aber ist sicherlich etwas flexibler. Das ganze komplett ohne Datenbank zu machen, halte ich nur bedingt für sinnvoll. Bei einfachen Aufräum-Scripten ok, bei ernsthafteren Jobs vielleicht nicht unbedingt.
Die rand()-Lösung ist natürlich sehr abhängig von der Anzahl der Zugriffe. Wenn mein Script zB nachts nur sehr selten aufgerufen wird ist die Wahrscheinlichkeit eines Treffers ziemlich gering. Ob das hinnehmbar ist hängt sicherlich stark vom Anwendungsfall ab.
Eventuell wäre eine Kombination der erwähnten „Inline-Cronjobs“ und der Zufallsmethode sinnvoller; ich prüfe halt nicht bei jedem Aufruf ob ein Job gestartet werden muß sondern nur mit einer gewissen (allerdings eher hohen) Wahrscheinlichkeit.
Nur so eine Idee, könnte man für sowas nicht auch http://de.php.net/apc_store verwenden (Counter speichern)?
Da es einige kostenlose Cronjobdienste gibt, sehe ich eigentlich keine Notwendigkeit für solche Workarounds mehr. Man muss bei der Verwendung eines solchen Dienstes natürlich Vorkehrungen treffen. Wenn man im Script sicherstellt dass es nur von einem bestimmten Host (dem Cronjob-Anbieter) abgerufen werden darf, dann ist die Wahrscheinlichkeit ungewollter Abrufe schon sehr gering.
man könnte allerdings auch einfach nach jedem durchführen über apc_store eine Variable mit TTL 24h (oder was man benötigt) anlegen, und kontrolliert dann nur noch ob die Variable vorhanden ist.
ps: warum gibt’s hier kein editieren?
Die apc_store Methode macht mich neugierig. Vielleicht will Salz ja was in seinem Blog was drüber schreiben. Hier geht natürlich auch.
Auf APC zuzugreifen ist hierbei bestimmt eine nette Lösung, jetzt kommt das aber. Falls der User schon keine Cronjobs zur verfügung hat, wir er bestimmt auch die kein PECL installieren können und dies ist für APC ja Vorraussetzung.
besser mt_rand( ) verwenden, wenn’s um gleichverteilte zufallszahlen geht. wir hatten vor einiger zeit einen thread zu diesem thema bei selfphp. schau dir mal die grafiken in meinem post an:
http://www.selfphp.de/forum/showthread.php?t=20507
cx
Alles ganz nett. Immerhin gibt es noch die Möglichkeit von kostenlosen Cronjobs, wenn diese auch recht unzuverlässig sind, und immer seltener werden. Auch bei größeren Communitys mit vielen Zugriffen rund um die Uhr würde ich mich nicht unbedingt auf die pünktliche Ausführung bei wichtigen Anwendungen verlassen.
Ein Programmierer sollte doch die nötigen Verbindungen zu anderen Gleichgesinnten haben, bei denen man sich so etwas ausleihen kann. 😉