Passer au contenu principal

Triggers

Les triggers sont responsables du démarrage automatique du job. Il en existe 4 types. Les plus courants sont les triggers de type « filtre de messages » , mais il existe aussi les triggers de type « cron », « flux » et « échec ».

Types de trigger

Triggers de filtre de messages

Les triggers de filtre de messages surveillent les messages entrants et vérifient si les données dans ces messages correspondent à leurs critères d'inclusion et ne répondent pas à leurs critères d'exclusion. S'ils réussissent ces tests et s'il y a des jobs actifs configurés pour utiliser ce trigger, une exécution sera lancée pour chaque combinaison message/job.

En tant qu'utilisateur, vous spécifiez les critères d'inclusion et d'exclusion qui déterminent les messages entrants qui doivent déclencher l'exécution des jobs. En gros, si une partie d'un corps de message correspond au JSON que vous fournissez comme filtre d'inclusion, et ne correspond pas au JSON que vous avez fourni comme filtre d'exclusion, un job s'exécutera (en supposant que vous en avez créé un avec autoprocess activé).

Le critère de filtrage prend la forme d'une chaîne de caractères JSON valide, comme ceci : {"Name":"Aleksa Iwobi"}. Dans une requête SQL, cette chaîne sera utilisée dans la clause WHERE et utilisera des opérateurs spéciaux de jsonb comme celui-ci :

SELECT * FROM messages
WHERE body::jsonb @> '{"Name":"Nicholas Pépé"}'::jsonb;

Si vous fournissez des critères d'exclusion comme {"type": "fake-data"} la requête résultante ressemblera à quelque chose comme ceci :

SELECT * FROM messages
WHERE body::jsonb @> '{"Name":"Nicholas Pépé"}'::jsonb
AND NOT (body::jsonb @> '{"type":"fake-data"}'::jsonb);

Il y a une explication plus détaillée de la correspondance des filtres ci-dessous.

Triggers Cron (anciennement minuteurs)

Cron triggers run jobs based on a cron schedule. Ils peuvent fonctionner aussi fréquemment qu'une fois toutes les minutes, ou aussi rarement que vous le souhaitez, et peuvent être programmés à des dates ou des heures très précises. Chaque fois qu'un job chronométré réussit, son final_state est sauvegardé et utilisé comme initial_state pour sa prochaine exécution. Voir « Gérer l'état » et « Garder un curseur » ci-dessous pour une aide à l'implémentation.

La meilleure façon d'apprendre à connaître cron, si vous n'êtes pas déjà familier, est à travers l'interface OpenFn ou

crontab.guru.

Triggers de flux

Les triggers de flux exécutent un job après qu'un autre job spécifié se termine avec succès. Par exemple, un trigger de flux qui spécifie l'exécution réussie du Job A peut être utilisé pour le Job B. Chaque fois que le Job A réussit, le Job B commence à s'exécuter avec le final_state du Job A comme son initial_state.

Triggers d'échec

Les triggers d'échec, ou « catch », fonctionnent comme les triggers de flux, sauf qu'ils guettent l'échec, plutôt que le succès, d'un job spécifique. (par exemple, le Job A paie un ASC via MPESA. Si le Job A échoue, nous devons lancer le Job B, qui envoie un SMS au responsable du district lui demandant de payer manuellement l'ASC.)

Traitement des jobs cron

Traitement à la demande pour les jobs cron. Si vous exploitez les triggers cron pour exécuter des jobs à des moments précis, vous pouvez également exécuter ce job déclenché par cron à la demande. De cette façon, vous n’avez pas à attendre l'expiration de la minuterie avant de procéder au test ! Il suffit simplement de cliquer sur le bouton Processus/« Jouer » maintenant disponible sur les pages Job, Run et Activity History.

Exécute le bouton de trigger de temps d'exécution de la liste

Bouton de trigger de l'historique de l'exécution

Maintien d'un curseur en state pour les jobs de minuterie

Comme de nombreux jobs de minuterie nécessitent de garder une sorte d'enregistrement de leur exécution précédente pour modifier leurs actions ultérieures, state est transmis entre les exécutions. Un exemple pourrait être de conserver un « curseur » pour ne sélectionner que les nouveaux enregistrements dans une base de données. On s'attendrait à la logique suivante :

  1. job-1 récupère les patients de la base de données
  2. job-1 fait quelque chose d'important avec ces dossiers de patients
  3. job-1 enregistre l'id du dernier patient traité avec succès à final_state
  4. quand job-1 s'exécute à nouveau, il récupère les patients dont l'id est supérieur à l'id du dernier patient traité avec succès.

Pour y parvenir, vous pourriez écrire :

fetchPatient({ type: 'referral', offset: state.lastId }, state => {
// Assuming the system returned an array of patients in the "data" key.
state.lastId = state.data.patients.sort((a, b) => b.id - a.id)[0];
return state;
});

Le décalage initial sera null, mais les exécutions suivantes vont automatiquement récupérer seulement les « nouveaux » patients.

Gestion de la taille de state pour les jobs de minuterie

Etant donné que l'état est transmis entre chaque exécution d'un job de minuterie, si votre job ajoute quelque chose de nouveau à l'état à chaque exécution, il peut rapidement devenir trop grand pour être traité de manière pratique. Imaginez qu'une réponse du serveur ajoutait, via array.push(...), à state.references chaque fois que le job est exécuté. OpenFn supporte jusqu'à 50 000 octets (via Erlang's byte_size), bien que la plupart des octets final_state se situent entre 100 et 1000.

Si la taille de votre final_state dépasse 10 000 octets, OpenFn enverra aux collaborateurs du projet un email d'avertissement. Si elle dépasse 50 000 octets, votre exécution va toujours réussir mais son final_state ne sera pas sauvegardé et la prochaine fois que le job sera exécutée il héritera de l'état final précédent, non mis à jour. (p. ex. le dernier état qui était < de 50 000 octets.)

Une solution rapide pour l'état final bloat

Le plus souvent, l'état final bloat est dû à une gestion incorrecte de state.references ou state.data. Cela peut être corrigé en ajoutant les lignes suivantes : either à la fonction callback de votre paquetage de langue (s'il en permet un) ou en ajoutant une opération alterState(. .) après votre opération.

alterState(state => {
state.custom = somethingIntentional;
state.data = {};
state.references = [];
return state;
});

La correspondance des filtres en détail

Pour illustrer la correspondance des filtres, reportez-vous aux exemples de filtres et de messages ci-dessous.

  • Le message « a » correspondra au filtre 1, mais pas le message « b ».
  • Le message « c » correspondra au filtre 2, mais pas le message « d ».

Filtre 1, inclusion simple

Les critères d'inclusion sont { "formID": "patient_registration_v7" } et les critères d'exclusion sont laissés vides.

Le message « a » correspondra

{
"submissionDate": "2016-01-15",
"formID": "patient_registration_v7",
"name": "Jack Wilshere",
"dob": "1986-05-16",
"medications": ["anaphlene", "zaradood", "morphofast"]
}

Le message « b » ne correspondra pas

{
"submissionDate": "2016-01-16",
"formID": "patient_registration_v8",
"name": "Larry Bird",
"dob": "1982-03-21",
"medications": ["anaphlene", "zaradood", "morphofast"]
}

Le message « b » n'inclut pas "formID":"patient_registration_v7" et ne correspond pas au filtre « 1 ».

Filtre 2, inclusion et exclusion

Le critère d'inclusion est { "name": "john doe" } et le critère d'exclusion est {"allowedToShare": false}.

Le message « c » correspondra

{
"submissionDate": "2016-01-15",
"name": "john doe",
"dob": "1986-05-16"
}

Le message « d » ne correspondra pas

{
"submissionDate": "2016-01-15",
"name": "john doe",
"dob": "1986-05-16",
"allowedToShare": false
}

Autres échantillons de filtres

Correspond aux messages WHERE le formId est "Robot_Photo_21.04.2015"

inclusionexclusion
{ "formId": "Robot_Photo_21.04.2015" }

Faire correspondre un message avec deux fragments à l'intérieur d'un tableau appelé data

(Ceci est utile lors de la collecte de données via ODK)

inclusionexclusion
{ "data": [{ "outlet_call": "TRUE", "new_existing": "Existing" }] }

Faire correspondre un message WHERE et AND qui sont tous les deux inclus

inclusionexclusion
{ "formId": "Robot_Photo_21.04.2015", "secret_number": 8 }

Faire correspondre un message en utilisant l'exclusion

inclusionexclusion
{ "formId": "Robot_Photo_21.04.2015" }{ "safeToProcess": false }

Faire correspondre un message avec un fragment à l'intérieur d'un autre objet appelé form

inclusionexclusion
{"form": {"@xmlns": "http://openrosa.org/formdesigner/F732194-3278-nota-ReAL-one"}}

Une démo d'exclusion

Imaginez que nous ayons un filtre qui inclut des messages avec form == 'bns_survey' mais nous voulons ensuite commencer en excluant ceux qui ont body.survey_type == 'practice'. Notre trigger de filtre devrait ressembler à ceci :

inclusionexclusion
{ "form": "bns_survey" }{"body": {"survey_type": "practice"}}

Nous l'avons configuré à partir du formulaire de trigger comme ceci :

img

Et vérifiez le résultat dans l'inbox :

img