Asynchrone Skripte kommen zum Einsatz, wenn die bestimmen Operationen nicht mehr Realtime ausgeführt werden können - da sie entweder zu viel Zeit oder Rechnerleistung benötigen würden.

Es gibt mehrere Möglichkeiten asynchrone Aufgaben für und mit Drupal zu lösen:

  • Drupal Cron Hook
  • Skript ohne Drupal Bootstrap
  • PHP Skript mit Drupal Bootstrap
  • PHP Skript mit Drush

Drupal Cron Hook

Vorteile

  • einfacher Einsatz ohne Kommandozeile

Nachteile

  • Laufzeitbegrenzung PHP Skript (durch Webserver)
  • Periodisierung schwieriger bzw. im Konflikt mit anderen Drupal Cron-Hook Periodisierungen (=> Perfomance-Probleme)

Wenn es um schnelle und unkomplizierte Aufgaben geht, ist der Drupal Cron-Hook die Wahl Nummer 1. Der Cron Hook wird ausgeführt, wenn die cron.php von Drupal ausgeführt wird. Der kürzeste Zeitabstand richtet sich also nach der Häufigkeit der Ausführung der Drupal cron.php.

PHP Skript mit Drupal Bootstrap

Vorteile

  • Drupal Funktionen im Skript nutzbar
  • Datenbank sofort nutzbar (über Drupal Funktionen)

Nachteile

  • Kommandozeilen Handling umständlich

Hier ein Beispiel, wie man einen neuen Node erzeugt:

<?php

if ((!empty($_SERVER['argv'][1])) && (!empty($_SERVER['argv'][2]))) {

  if (!file_exists($_SERVER['argv'][1] .'/index.php')) {
    print("invalid drupal path\n");
    exit;
  }
}
else {
  print("parameter missing: frist parameter should absolute path to drupal, second paramenter hostname\n");
  exit;
}

$sapi_type = php_sapi_name();
if ($sapi_type!='cli')  die('only executable from command line!');

// Drupal Bootstrap laden
chdir($_SERVER['argv'][1]);
$_SERVER['HTTP_HOST'] = $_SERVER['argv'][2];
$_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'] = '/index.php';
require_once('includes/bootstrap.inc');

drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

switch ($_SERVER['argv'][3]) {
  case 'meine_aktion':
    // nun wird der Node angelegt
    $node = new stdClass();
    $node->title    = 'Ich bin ein Node';
    $node->type     = 'story';
    $node->body   = 'Die Welt ist schön';
    $node->teaser = node_teaser($node->body);
    node_invoke_nodeapi($node, 'prepare');
    node_save($node);
    break;

  default:
    die('Nichts zu tun.');
}

Das Skript muss mit folgendem Kommando aufgerufen werden:

/usr/bin/php /www/drupal6/sites/default/modules/custom/mein_skript.php /www/drupal6 www.meinedomain.de meine_aktion

Der erste Parameter des Skriptes muss der absolute Pfad zum Drupal Hauptverzeichnis sein. Der zweite Parameter ist der Hostname, über den das Projekt über den Browser erreichbar ist. Beides wird benötigt, um die Konfiguration des Projektes richtig einzulesen (das funktioniert auch mit Multisite Umgebungen so). Der letzte Parameter legt dann fest, welche Aktion im Skript ausgeführt werden soll.

Das ganze sieht ziemlich unsauber aus und es muss ziemlich viel vorbereitet werden, bevor man die eigentliche Aktion ausführen muss. Nicht war? Die bessere Lösung ist Drush als API für das eigene Shellskript zu verwenden.

PHP Skript mit Drush

Vorteile

  • Drupal Funktionen im Skript nutzbar
  • Datenbank sofort nutzbar (über Drupal Funktionen)
  • Standardisierte Schnittstelle zu Kommanozeile über Drush

Nachteile

  • Zusätzliche Module müssen in Drupal aktiv sein (Drush, Drush_mm, u.s.w.)

Folgendes Skript wird angelegt, um einen Node anzulegen:

$node = new stdClass();
$node->title    = 'Ich bin ein Node';
$node->type     = 'story';
$node->body   = 'Die Welt ist schön';
$node->teaser = node_teaser($node->body);
node_invoke_nodeapi($node, 'prepare');
node_save($node);

Der Aufruf des Skriptes erfolgt mit folgenden Befehl:

drush eval "require_once('/www/drupal6/sites/default/modules/custom/mein_skript.php');"

Um den Bootstrap kümmert sich Drush und die Konfiguration der Installationsumgebung kann über Drush Parameter festgelegt werden. Wie man Drush verwendet wird im Artikel Arbeiten mit Drush aufgezeigt.

Automatisches Ausführen

Da ein asynchrones Skript nicht in Realtime durch beispielsweise einen Klick auf die Webseite ausgelöst wird, müssen diese in regelmäßigen Abständen periodisch ausgeführt werden. Die Größe der zeitlichen Periode ist stark von der Funktion abhängig. Besonders vorsichtig muss man dabei sein, dass die Laufzeit eines Skriptes niemals die Länge des festgelegten periodischen Zeitintervals überschreitet. Ist dies der Fall, kann es passieren, dass mehrerer Skripte parallel ausgeführt werden. Als Folge davon wird eventuell der ganze Server lahm gelegt. Es gibt zwei Möglichkeiten dies zu vermeiden:

  • ausreichend große Zeitperiode Sofern die Möglichkeit besteht eine Zeitperiode mit genügend Buffer zu wählen, ist diese Lösung die schnellste und einfachste
  • Einsatz von Semaphoren Semaphoren werden dazu eingesetzt um zu verhindern, dass zwei oder mehrere Prozesse gleichzeitig ausgeführt werden. Ist das betroffene Skript schon aktiv, wird ein neues Ausführen des Skriptes verhindert, solange dessen Prozess noch aktiv ist. Entweder verwendet man die PHP eigenen Funktionen für den Einsatz oder baut sich eine eigene Lösung mit Hilfe einer Statusdatei (oder auch ein Flag in einer DB).

Weitere Informationen

Aktualisiert: