Comment créer un type d'opération programmée supplémentaire
EMu fournit trois fonctions d’Opérations programmées par défaut :
Dans cette section, nous voyons comment les Administrateurs Système peuvent créer un type supplémentaire d'Opération programmée.
Chaque type d’Opération programmée (par exemple, Supprimer, Fusionner, etc.) est définie par un script qui réside sous le répertoire etc/operations
ou local/etc/operations sur le serveur EMu.
Note: Lorsque vous ajoutez un script pour un type supplémentaire d’Opération programmée pour votre système EMu, placez-le sous local/etc/operations
pour éviter le risque qu’il soit écrasé lors de mises à jour d'EMu.
Le script inclut le nom de l'opération qui sera listée dans la liste déroulante Type : (Opération) sur l'onglet Opération du module Opérations programmées.
Lorsque le processus emuoperations
s'exécute il scanne les répertoires etc/operations et local/etc/operations pour localiser les scripts pour tous les types d’Opérations programmées (fichiers qui se terminent par une extension .pl) et enregistre un nom pour chaque type d'opération trouvé. L'exemple suivant enregistre l’Opération programmée Supprimer (Delete) :
sub
Register
{
my $plugins = shift;
#
# We handle the "Delete" method.
#
$plugins->{"Delete"} = \&Delete;
}
Quand un nouveau type d'Opération programmée est ajouté à EMu, une entrée de Liste de consultation doit être ajoutée à la Liste de consultation Type Opération. Pour l'exemple ci-dessus, un enregistrement Liste de consultation a été ajouté à la Liste de consultation Type Opération avec une valeur de Delete
:
Lors de la planification d'une opération dans un enregistrement dans le module Opérations programmées, l'opération peut être programmée pour commencer :
- A un moment spécifié
-OU-
- Immédiatement
Si Commencer : (Exécution) est défini sur Immédiatement, l'opération sera appelée dès que l'enregistrement Opérations programmées sera sauvegardé. L'opération commencera à s'exécuter sur le serveur EMu et le contrôle sera rendu à l'utilisateur pour qu'il continue son travail.
Si Commencer : (Exécution) est réglé sur À un moment spécifié, l'opération sera invoquée par le script emuoperations
sur le serveur EMu en temps voulu.
Note: L'exécution de chaque opération en attente consomme une licence de la même manière qu'un utilisateur consommerait une licence pour effectuer la tâche. Comme pour les utilisateurs effectuant des tâches, plusieurs opérations peuvent être exécutées simultanément jusqu'à la limite de licence du système.
Le script emuoperations
est conçu pour être exécuté à partir de cron avec une entrée similaire à la suivante :
30 17 * * * /home/ke/emu/client/bin/emurun emuoperations 2>&1 | /home/ke/emu/client/bin/emurun emulogger -t "KE EMu Operations" -z operations
Le script est typiquement exécuté une fois par jour, mais peut être configuré pour s’exécuter un nombre illimité de fois pendant la journée. Lorsque le script emuoperations
s'exécute, il cherche les opérations qui étaient planifiées pour être exécutées avant la date et heure actuelles et les lance.
Note: La date et l'heure spécifiées dans un enregistrement Opérations programmées sont le moment le plus tôt où l'opération sera exécutée. L'heure réelle à laquelle une opération est exécutée dépend de l'heure à laquelle le script emuoperations
est programmé : emuoperations est le script utilisé pour exécuter une opération programmée dans un enregistrement du module Opérations planifiées. Lorsque emuoperations s'exécute, il cherche les opérations planifiées pour être exécutées avant la date et heure actuelles et les lance. Ainsi, si emuoperations est programmé pour s'exécuter une fois par jour, il commencera toute opération planifiée pour s'exécuter dans les 24 heures précédentes : en théorie, une opération pourrait avoir été planifiée pour s'exécuter 23 heures et 59 minutes plus tôt. Si emuoperations doit être exécuté une fois par jour, il est probablement judicieux de programmer des opérations proches de l'heure d’exécution de emuoperations. Il est également possible d'exécuter emuoperations à différents moments de la journée.
emuoperations
ré-exécutera également toutes les opérations précédentes qui n'ont pas abouties.
Chaque type d’Opération programmée enregistre une fonction qui est appelée pour traiter l'opération. Par exemple, l’Opération programmée Supprimer (Delete) est effectuée par une fonction enregistrée appelée Delete
.
sub
Register
{
my $plugins = shift;
#
# We handle the "Delete" method.
#
$plugins->{"Delete"} = \&Delete;
}
La fonction est passée deux paramètres :
- Une session IMu qui permet d'accéder aux enregistrements EMu pour effectuer l'opération.
- Un hachage des données à partir d'un enregistrement Opérations programmées avec les détails sur cette opération particulière (c.-à-d. quand, quels enregistrements sont affectés, quel module, etc.).
sub
Delete
{
my $imusession = shift;
my $record = shift;
#
# Run the "Delete" operation.
#
...
}
La liste des clés disponibles dans le hachage sont :
|
L’IRN (NEI) d'un enregistrement dans le module Opérations programmées avec les détails sur cette opération programmée. |
|
Le nom de l'opération. |
|
Le type d'opération. |
|
Le module sur lequel l'opération doit être exécutée. |
|
L’IRN cible pour l'opération Fusionner. |
|
La liste des IRN que l'opération doit traiter. |
|
La liste des IRN que l'opération a déjà traités. Note: Généralement, ce sera une liste vide, sauf si une opération a échoué. |
|
Le répertoire qui contient les fichiers / informations requis par une opération pour le traitement. |
|
Un identificateur à ajouter aux enregistrements mis à jour dans le cadre de l'exécution de l'opération. |
Les valeurs pour les clés sont accessibles via le paramètre $record
par exemple :
$record->{Module}
-OU-
@{$record->{IrnsToProcess}}
Dans cet exemple, une liste d’IRN (NEI) est supprimée :
#!/usr/bin/perl
use strict;
use warnings;
use lib "$ENV{EMUPATH}/utils/imu/lib";
use IMu::Module;
#
# Registration function.
#
no warnings 'redefine';
sub
Register
{
my $plugins = shift;
#
# We handle the "Delete" method.
#
$plugins->{"Delete"} = \&Delete;
}
use warnings 'redefine';
#
# The handler for the "Delete" operation
#
sub
Delete
{
my ($imusession, $record) = @_;
my ($attachments, $start, @deleteirns, $irn, $i);
#
# Check that we have the required information
#
if (! defined($record->{IrnsToProcess}) || @{$record->{IrnsToProcess}} == 0)
{
FileLog("Error: no irns supplied for deletion");
return(1);
}
elsif (! defined($record->{Module}) or $record->{Module} eq "")
{
FileLog("Error: delete module is not defined");
return(1);
}
#
# Get the other information that we need to process
#
$attachments = GetAttachmentFields($record->{Module});
@deleteirns = @{$record->{IrnsToProcess}};
$start = GetStartPosition($record);
FileLog("Running DELETE plugin for $record->{Module}");
FileLog("%d records scheduled for deletion, starting at position $start", scalar(@deleteirns));
#
# Now delete each record in turn
#
for ($i = $start; $i < @deleteirns; $i++)
{
$irn = $deleteirns[$i];
FileLog("Deleting irn $irn...");
last if (! ProcessDeletion($imusession, $attachments, $irn, $record));
AddToProcessed($irn);
}
return($i != @deleteirns);
}
#
# Do the actual deletion work
#
sub
ProcessDeletion
{
my ($imusession, $attachments, $irn, $record) = @_;
my ($table, $colname, $module, @matches, $hits, %found, $key, $column);
eval
{
%found = ();
foreach $key (keys %{$attachments})
{
#
# The assignment here is unusual but it gets around an
# odd foreach scoping problem after an exception is thrown.
#
$table = $key;
$module = IMu::Module->new($table, $imusession);
foreach $column (keys %{$attachments->{$table}})
{
#
# Find records which match this irn
#
$colname = $column;
$hits = $module->findTerms([$colname, $irn]);
next if ($hits <= 0);
#
# Add records to found hash
#
FileLog("Found $hits matches for $colname in $table");
push(@{$found{$table}->{$colname}}, GetMatches($module));
}
}
};
if ($@)
{
FileLog("Error: failed to process $colname in $table for irn $irn: $@");
return(0);
}
@matches = keys %found;
if (@matches)
{
#
# Log that we cannot delete the record
#
FileLog("Unable to delete irn $irn because it is attached in the following places:");
foreach $table (@matches)
{
foreach $colname (keys %{$found{$table}})
{
FileLog("\tModule: $table, Column: $colname, Record(s): " . join(", ", @{$found{$table}->{$colname}}));
}
}
}
else
{
#
# Delete the record
#
DeleteRecord($imusession, $irn, $record);
}
#
# Add irn to processed
#
return(1);
}
#
# Delete the record
#
sub
DeleteRecord
{
my ($imusession, $irn, $record) = @_;
my ($module, $hits, $result);
eval
{
$module = IMu::Module->new($record->{Module}, $imusession);
$hits = $module->findKey($irn);
if ($hits > 0)
{
$result = $module->remove("start", 0, 1);
if ($result == 0)
{
FileLog("Failed to delete irn $irn from $record->{Module}");
}
}
else
{
FileLog("Failed to find irn $irn in $record->{Module}");
}
};
if ($@)
{
FileLog("Failed to delete $irn from $record->{Module}: $@");
}
}
#
# Get all the records that match the attachment query
#
sub
GetMatches
{
my ($module) = @_;
my ($result, @matches, $row);
#
# Get all of the records at once
#
@matches = ();
$result = $module->fetch("start", 0, -1, "irn");
if ($result->{count})
{
#
# Get the irn for each row and push it to the list of matches
#
foreach $row (@{$result->{rows}})
{
push(@matches, $row->{irn});
}
}
return(@matches);
}
1;