Ich würde gerne wissen, ob es einen Weg gibt, einen Cronjob/eine Aufgabe zu erstellen, um jede Minute auszuführen. Derzeit sollte jede meiner Instanzen diese Aufgabe ausführen können.
Dies ist, was ich in den Config-Dateien ohne Erfolg versucht habe:
container_commands:
01cronjobs:
command: echo "*/1 * * * * root php /etc/httpd/myscript.php"
Ich bin mir nicht wirklich sicher, ob dies der richtige Weg ist
Irgendwelche Ideen?
Erstellen Sie im Stammverzeichnis Ihrer Anwendung einen Ordner mit dem Namen .ebextensions, falls er noch nicht vorhanden ist. Erstellen Sie dann eine Konfigurationsdatei im Ordner .ebextensions. Ich benutze example.config zu Illustrationszwecken. Dann fügen Sie dies zu example.config hinzu
container_commands:
01_some_cron_job:
command: "cat .ebextensions/some_cron_job.txt > /etc/cron.d/some_cron_job && chmod 644 /etc/cron.d/some_cron_job"
leader_only: true
Dies ist eine YAML-Konfigurationsdatei für Elastic Beanstalk. Stellen Sie sicher, dass Sie beim Kopieren in Ihren Texteditor Leerzeichen anstelle von Tabulatoren verwenden. Andernfalls erhalten Sie einen YAML-Fehler, wenn Sie dies auf EB drücken.
So erstellen Sie einen Befehl mit dem Namen 01_some_cron_job. Befehle werden in alphabetischer Reihenfolge ausgeführt, so dass 01 als erster Befehl ausgeführt wird.
Der Befehl nimmt dann den Inhalt einer Datei mit dem Namen some_cron_job.txt und fügt ihn einer Datei mit dem Namen some_cron_job in /etc/cron.d hinzu.
Der Befehl ändert dann die Berechtigungen für die Datei /etc/cron.d/some_cron_job.
Die Taste leader_only stellt sicher, dass der Befehl nur in der ec2-Instanz ausgeführt wird, die als Leader betrachtet wird. Anstatt auf jeder ec2-Instanz zu laufen, die Sie möglicherweise ausgeführt haben.
Erstellen Sie anschließend eine Datei mit dem Namen some_cron_job.txt im Ordner .ebextensions. Sie werden Ihre Cron-Jobs in dieser Datei ablegen.
Also zum Beispiel:
# The newline at the end of this file is extremely important. Cron won't run without it.
* * * * * root /usr/bin/php some-php-script-here > /dev/null
Dieser Cron-Job wird also zu jeder vollen Stunde als Root-Benutzer ausgeführt und die Ausgabe nach/dev/null verworfen./usr/bin/php ist der Pfad zu PHP. Ersetzen Sie dann ein PHP-Skript mit dem Pfad zu Ihrer PHP-Datei. Dies setzt natürlich voraus, dass Ihr Cron-Job eine PHP -Datei ausführen muss.
Stellen Sie außerdem sicher, dass die Datei some_cron_job.txt am Ende der Datei einen Zeilenumbruch enthält, genau wie im Kommentar angegeben. Sonst läuft Cron nicht.
Update: Es gibt ein Problem mit dieser Lösung, wenn Elastic Beanstalk Ihre Instanzen skaliert. Angenommen, Sie haben eine Instanz, in der der Cron-Job ausgeführt wird. Sie erhalten mehr Traffic, so dass Sie mit Elastic Beanstalk auf zwei Instanzen skaliert werden können. Mit leader_only wird sichergestellt, dass zwischen den beiden Instanzen nur ein Cron-Job ausgeführt wird. Ihr Verkehr nimmt ab und Elastic Beanstalk reduziert Sie auf eine Instanz. Anstatt die zweite Instanz zu beenden, beendet Elastic Beanstalk die erste Instanz, die der Anführer war. Sie haben jetzt keine Cron-Jobs ausgeführt, da sie nur in der ersten Instanz ausgeführt wurden, die beendet wurde. Siehe die Kommentare unten.
Update 2: Verdeutlichen Sie dies anhand der folgenden Kommentare: AWS bietet jetzt Schutz gegen die automatische Instanzbeendigung. Aktivieren Sie es einfach in Ihrer Anführerinstanz und Sie können loslegen. - Nicolás Arévalo 28. Oktober 16 um 09:23
Laut aktuellen Dokumenten ist man in der Lage, periodische Aufgaben auszuführen in ihrer sogenannten Worker Tier .
Zitieren der Dokumentation:
AWS Elastic Beanstalk unterstützt periodische Aufgaben für Worker-Tiers in Umgebungen, in denen eine vordefinierte Konfiguration mit einem Lösungsstapel ausgeführt wird, der den Namen "v1.2.0" im Containernamen enthält. Sie müssen eine neue Umgebung erstellen.
Interessant ist auch der Teil über cron.yaml:
Um periodische Tasks aufzurufen, muss Ihr Anwendungsquellenpaket eine Datei cron.yaml auf der Stammebene enthalten. Die Datei muss Informationen zu den periodischen Aufgaben enthalten, die Sie planen möchten. Geben Sie diese Informationen mit der Standard-Crontab-Syntax an.
Update: Wir konnten diese Arbeit bekommen. Hier einige wichtige Beispiele aus unserer Erfahrung (Plattform Node.js):
eb ssh
) und führen Sie cat /var/log/aws-sqsd/default.log
aus. Es sollte als aws-sqsd 2.0 (2015-02-18)
berichten. Wenn Sie keine 2.0-Version haben, ist beim Erstellen Ihrer Umgebung ein Fehler aufgetreten, und Sie müssen eine neue erstellen, wie oben angegeben.In Bezug auf die Antwort von jamieb und die genannten Erwähnungen können Sie die Eigenschaft 'leader_only' verwenden, um sicherzustellen, dass nur eine EC2-Instanz den Cron-Job ausführt.
Zitat entnommen aus http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html :
sie können leader_only verwenden. Eine Instanz wird als Anführer in einer Auto Scaling-Gruppe ausgewählt. Wenn der Wert für leader_only auf true gesetzt ist, wird der Befehl nur in der Instanz ausgeführt, die als Leader markiert ist.
Ich bemühe mich, eine ähnliche Sache auf meiner Ebbe zu erreichen, also werde ich meinen Beitrag aktualisieren, wenn ich ihn löse.
UPDATE:
Ok, ich habe jetzt Cronjobs mit der folgenden EB-Konfiguration:
files:
"/tmp/cronjob" :
mode: "000777"
owner: ec2-user
group: ec2-user
content: |
# clear expired baskets
*/10 * * * * /usr/bin/wget -o /dev/null http://blah.elasticbeanstalk.com/basket/purge > $HOME/basket_purge.log 2>&1
# clean up files created by above cronjob
30 23 * * * rm $HOME/purge*
encoding: plain
container_commands:
purge_basket:
command: crontab /tmp/cronjob
leader_only: true
commands:
delete_cronjob_file:
command: rm /tmp/cronjob
Im Wesentlichen erstelle ich eine temporäre Datei mit den Cronjobs und stelle dann ein, dass die Crontab aus der temporären Datei gelesen wird. Anschließend lösche ich die temporäre Datei. Hoffe das hilft.
Wie bereits erwähnt, besteht der grundlegende Fehler bei der Einrichtung einer Crontab-Konfiguration darin, dass dies nur bei der Bereitstellung geschieht. Da der Cluster automatisch skaliert und wieder heruntergefahren wird, ist es vorzuziehen, dass der erste Server ebenfalls ausgeschaltet ist. Außerdem würde es kein Failover geben, was für mich kritisch war.
Ich recherchierte und sprach mit unserem AWS-Kontospezialisten, um die Ideen zu verbreiten und die Lösung zu bestätigen, die ich gefunden hatte. Sie können dies mit OpsWorks erreichen, obwohl es ein bisschen wie ein Haus ist, um eine Fliege zu töten. Es ist auch möglich, Data Pipeline mit Task Runner zu verwenden. Dies hat jedoch nur eingeschränkte Fähigkeiten in den Skripts, die ausgeführt werden können, und ich musste PHP - Skripts mit Zugriff auf den gesamten Code ausführen können Base. Sie können auch eine EC2-Instanz außerhalb des ElasticBeanstalk-Clusters reservieren, haben jedoch kein Failover mehr.
Hier ist also das, was ich mir ausgedacht habe, was anscheinend unkonventionell ist (wie der AWS-Vertreter kommentiert) und als Hack angesehen werden kann, aber es funktioniert und ist mit einem Fail-over solide. Ich habe eine Kodierungslösung mit dem SDK gewählt, die ich in PHP zeigen werde, obwohl Sie dieselbe Methode in jeder beliebigen Sprache verwenden können.
// contains the values for variables used (key, secret, env)
require_once('cron_config.inc');
// Load the AWS PHP SDK to connection to ElasticBeanstalk
use Aws\ElasticBeanstalk\ElasticBeanstalkClient;
$client = ElasticBeanstalkClient::factory(array(
'key' => AWS_KEY,
'secret' => AWS_SECRET,
'profile' => 'your_profile',
'region' => 'us-east-1'
));
$result = $client->describeEnvironmentResources(array(
'EnvironmentName' => AWS_ENV
));
if (php_uname('n') != $result['EnvironmentResources']['Instances'][0]['Id']) {
die("Not the primary EC2 instance\n");
}
Gehen Sie durch das und wie es funktioniert ... Sie rufen Skripts von Crontab aus, wie Sie es normalerweise bei jeder EC2-Instanz tun würden. Jedes Skript enthält dies am Anfang (oder enthält bei jeder Verwendung eine einzelne Datei), die ein ElasticBeanstalk-Objekt erstellt und eine Liste aller Instanzen abruft. Es verwendet nur den ersten Server in der Liste und prüft, ob es mit sich selbst übereinstimmt. Wenn dies der Fall ist, wird es fortgesetzt, andernfalls stirbt es und wird geschlossen. Ich habe nachgesehen und die zurückgegebene Liste scheint konsistent zu sein, was technisch gesehen nur eine Minute dauern muss, da jede Instanz den geplanten cron ausführt. Wenn es sich ändert, ist es egal, da es nur für dieses kleine Fenster relevant ist.
Dies ist in keiner Weise elegant, entspricht aber unseren spezifischen Anforderungen - die Kosten sollten nicht durch einen zusätzlichen Service erhöht werden oder es muss eine dedizierte EC2-Instanz vorhanden sein, die bei einem Ausfall zu einem Failover führen würde. Unsere cron-Skripts führen Wartungsskripts aus, die in SQS abgelegt werden. Jeder Server im Cluster hilft bei der Ausführung. Zumindest kann dies eine alternative Option sein, wenn es Ihren Bedürfnissen entspricht.
-Davey
Ich habe mit einem AWS-Supportmitarbeiter gesprochen, und so haben wir das für mich gemacht. 2015 Lösung:
Erstellen Sie eine Datei in Ihrem .ebextensions-Verzeichnis mit Ihrer_Dateiname.config . In der Eingabe für die Konfigurationsdatei:
dateien: "/etc/cron.d/cron_example": Modus: "000644" Besitzer: root Gruppe: Wurzel Inhalt: | * * * * * root /usr/local/bin/cron_example.sh "/usr/local/bin/cron_example.sh": Modus: "000755" Besitzer: root Gruppe: Wurzel Inhalt: | #!/bin/bash /usr/local/bin/test_cron.sh || Ausfahrt echo "Cron läuft am" Datum ">> /tmp/cron_example.log # Jetzt erledigen Sie Aufgaben, die nur in einer Instanz ausgeführt werden sollten ... "/usr/local/bin/test_cron.sh": Modus: "000755" Besitzer: root Gruppe: Wurzel Inhalt: | #!/bin/bash METADATA =/opt/aws/bin/ec2-Metadaten INSTANCE_ID = `$ METADATA -i | awk '{print $ 2}' ` REGION = `$ METADATA -z | awk '{print substr ($ 2, 0, Länge ($ 2) -1)}' ` # Finden Sie den Namen unserer Auto Scaling Group . ASG = `aws ec2 description-tags --filters" Name = Ressourcen-ID, Werte = $ INSTANCE_ID "\ --region $ REGION - Ausgabetext | awk '/ aws: Autoskalierung: Gruppenname/{print $ 5}' ` # Finden Sie die erste Instanz in der Gruppe FIRST = `aws autoscaling beschreiben-auto-scaling-groups --auto-scaling-Gruppennamen $ ASG\ --region $ REGION - Ausgabetext | awk '/ InService $/{print $ 4}' | sortieren | Kopf -1` # Testen Sie, ob sie gleich sind . ["$ FIRST" = "$ INSTANCE_ID"] Befehle: rm_old_cron: Befehl: "rm * .bak" cwd: "/etc/cron.d" ignoreErrors: true
Diese Lösung hat zwei Nachteile:
Problemumgehung:
Vorbehalt:
Sie müssen die IAM-Rollen nicht festlegen, wenn Sie die Standard-Beanstalk-Rolle verwenden.
Wenn Sie Rails verwenden, können Sie den Edelstein always-elasticbeanstalk verwenden. Sie können Cron-Jobs entweder für alle oder nur für eine Instanz ausführen. Es prüft jede Minute, um sicherzustellen, dass es nur eine "Leader" -Instanz gibt, und es wird automatisch ein Server zu "Leader" befördert, wenn es keinen gibt. Dies ist erforderlich, da Elastic Beanstalk während der Bereitstellung nur das Konzept der Führungslinie hat und während des Skalierens jederzeit eine Instanz herunterfahren kann.
UPDATE Ich habe auf AWS OpsWorks umgestellt und verwalte diesen Edelstein nicht mehr. Wenn Sie mehr Funktionalität benötigen, als in den Grundlagen von Elastic Beanstalk verfügbar ist, empfehle ich Ihnen dringend, zu OpsWorks zu wechseln.
Sie möchten wirklich keine Cron-Jobs auf Elastic Beanstalk ausführen. Da Sie über mehrere Anwendungsinstanzen verfügen, kann dies zu Race-Bedingungen und anderen Problemen führen. Ich habe eigentlich kürzlich darüber gebloggt (4. oder 5. Tipp weiter unten auf der Seite). Die Kurzversion: Verwenden Sie je nach Anwendung eine Jobwarteschlange wie SQS oder eine Drittanbieterlösung wie iron.io .
Eine besser lesbare Lösung, die files
anstelle von container_commands
verwendet:
Dateien: "/etc/cron.d/my_cron": Modus: "000644" Besitzer: root Gruppe: Wurzel Inhalt: | # Überschreibt die Standard-E-Mail-Adresse MAILTO = "[email protected]" # Führen Sie alle fünf Minuten einen Symfony-Befehl aus (als ec2-Benutzer) */10 * * * * ec2-user/usr/bin/php/var/app/current/app/console tun: etwas Kodierung: plain Befehle: # Sicherungsdatei löschen, die mit Elastic Beanstalk erstellt wurde. clear_cron_backup: Befehl: rm -f /etc/cron.d/watson.bak
Beachten Sie, dass das Format sich vom üblichen crontab-Format unterscheidet, indem es den Benutzer angibt, unter dem der Befehl ausgeführt werden soll.
Jemand wunderte sich über die automatischen Skalierungsprobleme von leader_only, wenn neue Leader auftauchten. Ich kann anscheinend nicht herausfinden, wie ich auf ihre Kommentare antworten soll, aber siehe diesen Link: http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto- Skalierungsumgebung/
Hier ist eine vollständige Erklärung der Lösung:
http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling-environment/
Mein 1-Cent-Beitrag für 2018
Hier ist der richtige Weg (mit Django/python
und Django_crontab
app):
in .ebextensions
Ordner erstellen Sie eine Datei wie diese 98_cron.config
:
files:
"/tmp/98_create_cron.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/sh
cd /
Sudo /opt/python/run/venv/bin/python /opt/python/current/app/manage.py crontab remove > /home/ec2-user/remove11.txt
Sudo /opt/python/run/venv/bin/python /opt/python/current/app/manage.py crontab add > /home/ec2-user/add11.txt
container_commands:
98crontab:
command: "mv /tmp/98_create_cron.sh /opt/elasticbeanstalk/hooks/appdeploy/post && chmod 774 /opt/elasticbeanstalk/hooks/appdeploy/post/98_create_cron.sh"
leader_only: true
Es muss container_commands
statt commands
sein.
hier ist eine Korrektur, wenn Sie dies in PHP tun möchten. Sie brauchen nur cronjob.config in Ihrem .ebextensions-Ordner, damit es so funktioniert.
files:
"/etc/cron.d/my_cron":
mode: "000644"
owner: root
group: root
content: |
empty stuff
encoding: plain
commands:
01_clear_cron_backup:
command: "rm -f /etc/cron.d/*.bak"
02_remove_content:
command: "Sudo sed -i 's/empty stuff//g' /etc/cron.d/my_cron"
container_commands:
adding_cron:
command: "echo '* * * * * ec2-user . /opt/elasticbeanstalk/support/envvars && /usr/bin/php /var/app/current/index.php cron sendemail > /tmp/sendemail.log 2>&1' > /etc/cron.d/my_cron"
leader_only: true
die Envvars ruft die Umgebungsvariablen für die Dateien ab. Sie können die Ausgabe in der Datei tmp/sendemail.log wie oben debuggen.
Hoffe das hilft jemandem, da es uns sicherlich geholfen hat!
Verwenden Sie den Instanzschutz, um zu steuern, ob Auto Scaling eine bestimmte Instanz beim Skalieren in beenden kann. Sie können die Instanzschutzeinstellung für eine Auto Scaling-Gruppe oder eine einzelne Auto Scaling-Instanz aktivieren. Wenn Auto Scaling eine Instanz startet, erbt die Instanz die Instanzschutzeinstellung der Gruppe Auto Scaling. Sie können die Instanzschutzeinstellung für eine Auto Scaling-Gruppe oder eine Auto Scaling-Instanz jederzeit ändern.
Du brauchst nur 2 Minuten um es zu konfigurieren:
installieren Sie Laravel-AWS-Arbeiter
composer require dusterio/laravel-aws-worker
fügen Sie dem Stammordner eine cron.yaml hinzu:
Fügen Sie cron.yaml zum Stammordner Ihrer Anwendung hinzu (dies kann ein Teil Ihres Repos sein .__ oder Sie können diese Datei direkt vor der Bereitstellung in EB hinzufügen. Wichtig ist, dass diese Datei zu diesem Zeitpunkt vorhanden ist von Bereitstellung):
version: 1
cron:
- name: "schedule"
url: "/worker/schedule"
schedule: "* * * * *"
Ihre gesamte Aufgabe in App\Console\Kernel
wird jetzt ausgeführt
Detaillierte Anweisungen und Erklärungen: https://github.com/dusterio/laravel-aws-worker
So schreiben Sie Aufgaben in Laravel: https://laravel.com/docs/5.4/scheduling
Wir haben also eine Weile mit diesem Problem zu kämpfen, und nach einigen Diskussionen mit einem AWS-Mitarbeiter habe ich endlich die Lösung gefunden, die meiner Meinung nach die beste Lösung ist.
Die Verwendung einer Worker-Ebene mit cron.yaml ist definitiv die einfachste Lösung. Was in der Dokumentation jedoch nicht klar ist, ist, dass dadurch der Job an das end der SQS-Warteschlange gestellt wird, die Sie zum Ausführen Ihrer Jobs verwenden. Wenn Ihre Cron-Jobs zeitabhängig sind (wie viele), ist dies nicht akzeptabel, da dies von der Größe der Warteschlange abhängt. Eine Option ist die Verwendung einer vollständig separaten Umgebung, nur um Cron-Jobs auszuführen, aber ich denke, das ist übertrieben.
Einige der anderen Optionen, z. B. das Überprüfen, ob Sie die erste Instanz in der Liste sind, sind ebenfalls nicht ideal. Was ist, wenn die aktuelle erste Instanz gerade heruntergefahren wird?
Instanzschutz kann auch zu Problemen führen - was ist, wenn diese Instanz eingesperrt/eingefroren wird?
Es ist wichtig zu verstehen, wie AWS die Funktionalität von cron.yaml selbst verwaltet. Es gibt einen SQS-Dämon, der eine Dynamo-Tabelle verwendet, um die "Anführerwahl" abzuwickeln. Es schreibt regelmäßig in diese Tabelle, und wenn der aktuelle Anführer nicht in kurzer Zeit geschrieben hat, übernimmt die nächste Instanz die Führung. Auf diese Weise entscheidet der Daemon, welche Instanz den Job in die SQS-Warteschlange auslösen soll.
Wir können die vorhandene Funktionalität wiederverwenden, anstatt zu versuchen, unsere eigene Funktionalität neu zu schreiben. Die vollständige Lösung finden Sie hier: https://Gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27
Das ist in Ruby, aber Sie können es problemlos an jede andere Sprache anpassen, die das AWS SDK enthält. Im Wesentlichen wird der aktuelle Anführer überprüft und anschließend der Zustand überprüft, um sicherzustellen, dass er in einem guten Zustand ist. Es wird so lange wiederholt, bis sich ein aktueller Anführer in einem guten Zustand befindet und wenn die aktuelle Instanz der Anführer ist, führen Sie den Job aus.
Basierend auf den Grundsätzen der Antwort von user1599237 , bei der Sie die Cron-Jobs auf allen Instanzen ausführen lassen, dann aber zu Beginn der Jobs bestimmen, ob sie ausgeführt werden dürfen, habe ich eine andere Lösung getroffen.
Anstatt auf die laufenden Instanzen zu schauen (und Ihren AWS-Schlüssel und Ihr Geheimnis zu speichern), verwende ich die MySQL-Datenbank, zu der ich bereits von allen Instanzen aus eine Verbindung herstelle.
Es hat keine Nachteile, nur positive:
Alternativ können Sie auch ein gemeinsam genutztes Dateisystem (wie AWS EFS über das NFS-Protokoll) anstelle einer Datenbank verwenden.
Die folgende Lösung wurde im PHP Framework Yii erstellt, Sie können sie jedoch problemlos für ein anderes Framework und eine andere Sprache anpassen. Auch der Exception-Handler Yii::$app->system
ist ein eigenes Modul. Ersetzen Sie es durch das, was Sie gerade verwenden.
/**
* Obtain an exclusive lock to ensure only one instance or worker executes a job
*
* Examples:
*
* `php /var/app/current/yii process/lock 60 empty-trash php /var/app/current/yii maintenance/empty-trash`
* `php /var/app/current/yii process/lock 60 empty-trash php /var/app/current/yii maintenance/empty-trash StdOUT./test.log`
* `php /var/app/current/yii process/lock 60 "empty trash" php /var/app/current/yii maintenance/empty-trash StdOUT./test.log StdERR.ditto`
* `php /var/app/current/yii process/lock 60 "empty trash" php /var/app/current/yii maintenance/empty-trash StdOUT./output.log StdERR./error.log`
*
* Arguments are understood as follows:
* - First: Duration of the lock in minutes
* - Second: Job name (surround with quotes if it contains spaces)
* - The rest: Command to execute. Instead of writing `>` and `2>` for redirecting output you need to write `StdOUT` and `StdERR` respectively. To redirect stderr to stdout write `StdERR.ditto`.
*
* Command will be executed in the background. If determined that it should not be executed the script will terminate silently.
*/
public function actionLock() {
$argsAll = $args = func_get_args();
if (!is_numeric($args[0])) {
\Yii::$app->system->error('Duration for obtaining process lock is not numeric.', ['Args' => $argsAll]);
}
if (!$args[1]) {
\Yii::$app->system->error('Job name for obtaining process lock is missing.', ['Args' => $argsAll]);
}
$durationMins = $args[0];
$jobName = $args[1];
$instanceID = null;
unset($args[0], $args[1]);
$command = trim(implode(' ', $args));
if (!$command) {
\Yii::$app->system->error('Command to execute after obtaining process lock is missing.', ['Args' => $argsAll]);
}
// If using AWS Elastic Beanstalk retrieve the instance ID
if (file_exists('/etc/elasticbeanstalk/.aws-eb-system-initialized')) {
if ($awsEb = file_get_contents('/etc/elasticbeanstalk/.aws-eb-system-initialized')) {
$awsEb = json_decode($awsEb);
if (is_object($awsEb) && $awsEb->instance_id) {
$instanceID = $awsEb->instance_id;
}
}
}
// Obtain lock
$updateColumns = false; //do nothing if record already exists
$affectedRows = \Yii::$app->db->createCommand()->upsert('system_job_locks', [
'job_name' => $jobName,
'locked' => gmdate('Y-m-d H:i:s'),
'duration' => $durationMins,
'source' => $instanceID,
], $updateColumns)->execute();
// The SQL generated: INSERT INTO system_job_locks (job_name, locked, duration, source) VALUES ('some-name', '2019-04-22 17:24:39', 60, 'i-HmkDAZ9S5G5G') ON DUPLICATE KEY UPDATE job_name = job_name
if ($affectedRows == 0) {
// record already exists, check if lock has expired
$affectedRows = \Yii::$app->db->createCommand()->update('system_job_locks', [
'locked' => gmdate('Y-m-d H:i:s'),
'duration' => $durationMins,
'source' => $instanceID,
],
'job_name = :jobName AND DATE_ADD(locked, INTERVAL duration MINUTE) < NOW()', ['jobName' => $jobName]
)->execute();
// The SQL generated: UPDATE system_job_locks SET locked = '2019-04-22 17:24:39', duration = 60, source = 'i-HmkDAZ9S5G5G' WHERE job_name = 'clean-trash' AND DATE_ADD(locked, INTERVAL duration MINUTE) < NOW()
if ($affectedRows == 0) {
// We could not obtain a lock (since another process already has it) so do not execute the command
exit;
}
}
// Handle redirection of stdout and stderr
$command = str_replace('StdOUT', '>', $command);
$command = str_replace('StdERR.ditto', '2>&1', $command);
$command = str_replace('StdERR', '2>', $command);
// Execute the command as a background process so we can exit the current process
$command .= ' &';
$output = []; $exitcode = null;
exec($command, $output, $exitcode);
exit($exitcode);
}
Dies ist das von mir verwendete Datenbankschema:
CREATE TABLE `system_job_locks` (
`job_name` VARCHAR(50) NOT NULL,
`locked` DATETIME NOT NULL COMMENT 'UTC',
`duration` SMALLINT(5) UNSIGNED NOT NULL COMMENT 'Minutes',
`source` VARCHAR(255) NULL DEFAULT NULL,
PRIMARY KEY (`job_name`)
)
Ich hatte eine andere Lösung dafür, wenn eine PHP-Datei durch cron ausgeführt werden muss und wenn Sie NAT -Instanzen gesetzt hätten, können Sie cronjob auf NAT setzen und die PHP-Datei über wget ausführen.