Trigger
Un trigger décrit une entrée événementielle gouvernée.
Il répond à la question :
quand cet événement arrive,
lance cette stratégie Touba,
avec ces limites,
si le manifest l'active explicitement.
Un trigger n’est pas un cron libre, un webhook direct ou un handler qui décide seul de lancer un agent. Dans Touba, le trigger compile vers l’AIR, le manifest l’active, le runtime vérifie, puis la trace rend l’acceptation ou le refus observable.
Syntaxe
trigger DailyResearchSchedule
on schedule "every 1s"
runs strategy DailyResearch
limits
max_runs_per_day as 1
timeout_ms as 30000
Touba accepte deux familles V1 :
trigger Name
on schedule "every 1s"
runs strategy StrategyName
limits
max_runs_per_day as 1
timeout_ms as 30000
trigger WebhookRun
on request POST "/webhook/run"
runs strategy StrategyName
with message as payload.message
limits
max_runs_per_day as 10
timeout_ms as 30000
Le runner schedule supporte les intervalles every <n>s, every <n>m et
every <n>h. Le service d’ingress HTTP route les triggers request selon la
méthode et le chemin déclarés. Sur un trigger request, une expression
payload.<champ> dans une clause with déclare qu’un argument de stratégie doit
être extrait du JSON entrant. Cette expression n’est pas une lecture générale du
payload : elle compile vers un contrat de mapping, et le corps HTTP brut n’est
pas stocké dans l’AIR, la queue, l’état ou la trace.
Exemple complet
module examples.daily_research
strategy DailyResearch
takes topic as Text
do
show
with message as "Daily research run: " ++ topic
trigger DailyResearchSchedule
on schedule "every 1s"
runs strategy DailyResearch
with topic as "daily review"
limits
max_runs_per_day as 1
timeout_ms as 30000
Manifest
Le trigger reste inactif tant que le manifest ne l’active pas.
{
"manifest_version": "touba-manifest-v1",
"triggers": {
"trigger:examples.daily_research/DailyResearchSchedule": {
"enabled": true,
"source": {
"kind": "schedule"
},
"limits": {
"max_runs_per_day": 1,
"timeout_ms": 30000
}
}
}
}
Le manifest peut restreindre une limite déclarée dans le code Touba. Il ne peut pas l’élargir silencieusement.
Runner foreground
touba trigger run daily_research.air.json \
--manifest touba.manifest.json \
--trigger trigger:examples.daily_research/DailyResearchSchedule \
--max-runs 1 \
--state touba.triggers.sqlite
Le runner attend l’intervalle déclaré, génère un événement normalisé, puis laisse
le runtime vérifier le manifest et les limites avant d’exécuter la stratégie.
--max-runs est obligatoire. Le registre SQLite est créé par défaut dans
.touba/triggers.sqlite ; --state permet de choisir son emplacement. L’état durable conserve les
event_id, les refus et la clé de jour UTC utilisée par max_runs_per_day.
Service webhook
touba trigger serve webhook.air.json \
--manifest touba.manifest.json \
--state touba.triggers.sqlite \
--queue touba.trigger-queue.sqlite \
--host 127.0.0.1 \
--port 8787 \
--trace-dir traces
Le service ouvre un endpoint HTTP pour chaque trigger request activé par le
manifest. Une requête POST /webhook/run est convertie en événement normalisé
source_kind=request, placée dans la queue durable touba-trigger-queue-v1,
puis exécutée par le runtime. Le payload HTTP brut n’est pas écrit dans la
queue, l’état ou la trace ; le service conserve les métadonnées nécessaires,
dont la taille et le digest SHA-256 du corps reçu.
Le manifest peut déclarer un contrat payload. Dans ce cas, le service accepte
uniquement le format, les content-types et la taille déclarés, puis extrait les
champs JSON listés dans payload.map. Ces champs deviennent les seuls arguments
persistés de la stratégie cible, et le runtime les revalide contre la signature
Touba avant l’exécution.
Quand le source Touba contient with message as payload.message, l’AIR porte le
contrat correspondant et touba manifest generate produit l’entrée
payload.map initiale :
{
"triggers": {
"trigger:examples.webhook/WebhookRun": {
"enabled": true,
"source": { "kind": "request" },
"limits": {
"max_runs_per_day": 10,
"timeout_ms": 30000
},
"payload": {
"format": "json",
"content_types": ["application/json"],
"max_bytes": 65536,
"map": {
"message": "$.message"
}
}
}
}
}
Le header x-touba-event-id permet à l’appelant de fournir une identité
d’événement stable. Si le même event_id est rejoué pour le même trigger, l’état
TD-1 provoque un refus TriggerReplayRejected avant de relancer la stratégie.
Sur une interface non loopback, le service exige --auth-token-env. Pour les
webhooks exposés à un fournisseur externe, --signature-secret-env ajoute une
vérification HMAC-SHA256 via x-touba-signature: sha256=<hex>. La queue remet en
attente les entrées processing périmées et peut marquer les échecs répétés en
dead_lettered.
Trace
Un run déclenché par trigger peut produire des événements comme :
trigger_event_receivedtrigger_event_acceptedtrigger_event_refusedtrigger_execution_startedtrigger_execution_completed
Les traces ne doivent pas contenir le payload externe brut, les secrets ou les credentials.
Contrat runtime
- Les entrées
scheduleetrequestgouvernées compilent vers l’AIR. - Le manifest active explicitement chaque trigger.
- Le runtime vérifie les limites avant l’exécution.
- Le service webhook persiste une queue
touba-trigger-queue-v1. - Le payload JSON entrant est contractualisé depuis le source Touba et le manifest.
- La signature HMAC-SHA256, les retries bornés, la reprise
processinget le dead-letter sont disponibles. - Les schedulers distribués, queues distribuées, adapters cloud, déclenchements directs d’agents, auto-discovery de manifest et sandbox système complète relèvent de couches plateforme séparées.