Cron-Job - viele Datenbankeinträge abarbeiten und mehrfache Scriptläufe

dwex

Erfahrenes Mitglied
Hallo Leute,

ich zerbreche mir schon seit Tagen den Kopf und komme nicht auf eine Lösung.

Ich habe folgendes:
Ich habe eine Datenbank mit vielen Einträgen. Diese Einträge muss ich an ein externes Script via fopen übergeben und erhalte einen Statuscode zurück. Das ganze dauert pro Eintrag etwa 1 Sekunde sodass ich zwischen 50 und 100 Einträge pro Minute verarbeiten kann (genau weis ich das natürlich nie wieviele es sind).
"Gleichzeitig" muss ich aber teilweise mehrere tausend Einträge verarbeiten.
Der CronJob läuft minütlich, da in den DB-Einträgen steht wann diese Daten übergeben werden sollen.

Jetzt war mein Lösungsansatz folgender:
Nach dem Scriptaufruf setze ich für alle DB-Einträge die zu diesem Zeitpunkt abgesendet werden sollen einen Flag in die DB nach dem Motto "wird bearbeitet" sodass vom nächsten Scriptaufruf, welcher ja in der nächsten Minute passiert, diese Einträge nicht mehr abgearbeitet werden.
Jetzt kommt das Problem - was mache ich wenn das Script einfach abbricht, sei es jetzt wegen eines Timeouts oder wegen eines Serverfehlers. Dann sind in der DB die Einträge als "wird bearbeitet" markiert - dies werden jedoch nie abgearbeitet.

Hat jemand eine Idee wie man das lösen könnte?

Vielen Dank im voraus für eure Hilfe!
 
Zuletzt bearbeitet:
Moin,

wenn es das RDBMS unterstützt, könntest du auf Transactions zurückgreifen, die dann ja erst beim abschließenden commit ausgeführt werden. Jedenfalls hoffe ich, dass die Aussage so stimmt, da ich damit selbst noch nicht gearbeitet habe - hab es nur so gelesen.

MfG aGeNET
 
Als ich Nutze MySQL - also sollte es das unterstüzen.
Kann mir das mit den Transactions jemand genauer erklären?
 
Zuletzt bearbeitet:
Als ich Nutze MySQL - also sollte es das unterstüzen.
Kann mir das mit den Transactions jemand genauer erklären?

Das ist nicht ganz korrekt. MySQL hat mehrere Storage-Engines. MyISAM unterstützt keine Transaktionen. InnoDB schon.

Kannst du das ganze etwas genauer beschreiben?
1 Datensatz pro Sekunde erscheint mir sehr langsam, normalerweise können es weite über 500 Datensätze je Sekunde sein. (je nach System)

Er meinte die Verarbeitung der Datensätze am externen Script. Darauf hat er keinen Einfluss.

Transaktionen kannst du damit machen
http://dev.mysql.com/doc/refman/5.1/de/lock-tables.html
wenn der Vorgang aber so langsam ist wird das ganze System ausfallen.

Transaktionen werden mit START TRANSACTION eingeleitet und COMMIT/ROLLBACK abgeschlossen. Das hat mit Locking erstmal nichts zu tun. http://dev.mysql.com/doc/refman/5.1/de/commit.html

Es löst IMHO auch das Problem nicht, da der Eintrag "wird bearbeitet" ohnehin erst mal eingetragen werden muss, um für andere Instanzen sichtbar zu sein. Ein SELECT wird solange nicht "wird bearbeitet" anzeigen, bis der COMMIT ausgeführt wurde.

Du könntest aber das "wird bearbeitet" erstmal eintragen, zusammen mit dem Start-Zeitpunkt, wann die Bearbeitung angefangen hat. Ist ein bestimmter Zeitpunkt (Start+maximale Bearbeitungszeit) erreicht, setzt der zweite Lauf des Cronjobs den Eintrag wieder zurück. Dies benötigt natürlich eine weitere Spalte in der DB und eine von dir definierte Bearbeitungszeit.

Meiner Meinung nach kannst du das Problem mit Transaktionen nicht lösen.
 
Hallo Saftmeister,

Richtig - die Laufzeit bestimmt das externe Script.

Deine Idee mit den Zeiten in der Tabelle werde ich mal durchdenken wie ich das am besten machen kann - danke dafür.

Hat sonst noch jemand eine Idee?
 
Ich möchte noch zu Transactions ergänzen, dass der Tabellentyp InnoDB erheblich schlechter performt als MyIsam. Bei einer solchen Menge Datensätze sollte man das bedenken.

Ich habe in einem uralten selbstgeschriebenen Forum ein ähnliches Problem gehabt. Dort wurden Bilder heruntergerechnet. Ich wusste mir damals auch nicht anders zu helfen, als es über einen Chronjob laufen zu lassen, weil die Skriptlaufzeit durch den Provider begrenzt war.

Ich hatte DREI Felder zur Steuerung in der DB.
1. Status (N=new, B=busy, E=error)
2. Starttime
3. Errorcounter

Bei deiner Menge an Datensätzen könnte es welche geben, die mögklicherweise innerhalb der "normalen" Laufzeit IMMER abbrechen. Solche Sätze sollte man möglichst erkennen und nicht ewig darauf herumrechnen lassen.

Ich hatte es so gelöst, dass bei jedem Lauf alle Sätze mit Status B und einer Starttime von vor 5 Minuten zurück auf Status N gesetzt wurde UND der Errorcounter wurde einen hochgezählt.

Dann wurden alle Sätze mit mehr als drei Fehlern auf Status E gesetzt. Diese wurden dann NICHT mehr bearbeitet, aber ich wurde über deren Anzahl bei meiner Anmeldung informiert und konnte mir ansehen, was das Problem war.

Etwas in dieser Art würde ich auch bei dir vorgehen.
 
Richtig - die Laufzeit bestimmt das externe Script.

Das meinte ich, was genau verstehst du unter externem Skript?
Liegt es auf einen anderen Server oder gehört es zu einer andere Anwendung****?

Ich sehe das Problem in der langsamen Ausführung. Je Sekunde einen Datensatz ist sehr langsam. Man sollte eventuell über eine andere Durchführungen nachdenken aber zu müsste man mehr darüber wissen.

Werden die Daten zB. wieder in einer DB gespeichert?

Wenn man mehrer Datensätze gleichzeitig überträgt, könnte das die Performance anheben und die Ausfälle reduzieren. Eventuell könnte man es in eine kleine multi Thread Anwendung packen. Oder oder oder ...

Liefert das externe Skript etwas zurück um die Übertragung abzusichern? Eventuell könntest du auch auf einen andere Skriptsprache ausweichen die nicht nach einer bestimmten Zeit abbricht zB. Shell Skripte.

Aber wie gesagt man müsste mehr über dein Vorhaben wissen um eine gute Lösung zu finden.


@SaftMaster: Danke, fürs berichtigen, du hast natürlich recht.
 
Hallo Napofis,

ich programmiere gerade eine "Anwendung" welche über mein CRM eingegebene SMS an einen SMS-Carrier über seine HTTPS-Schnittstelle an diesen übergibt. Die ganzen Daten werden dabei über eine encodierte-URL übergeben.
Hier erhalten ich dann für jeden aufruf ein XML-Konstrukt zurück welches unter anderem den Statuscode enthält welchen ich auswerte. Das sind teilweise sehr viele SMS (über 4.000) wenn ich die Option "SMS an alle Kunden wähle" um z.B. Statusmitteilungen zu versenden etc.

Die Übergabe dieser SMS dauert systembedingt etwa eine Sekunde, da ich ja von Carrier bereits die Statusmeldung für jede SMS zurückerhalte welcher dieser wiederum vom jeweiligen Netzbetreiber erhält. Hier ist dann z.B. auch eine Message-ID dabei die ich benötige um die Nachricht weiterverarbeiten zu können und evtl. Antworten wieder in mein System einzulesen und dem entsprechenden Kunden zu zuordnen.

An Multithread habe ich auch schon mal gedacht - mir ist jedoch kein Weg bekannt das mit PHP zu bewerkstelligen - lasse mich aber gerne eines Besseren belehren.
 
Zurück