Tâches et planificateur
Les tasks exécutent les traitements longs en dehors du rendu des pages : pas de délai maximal de rendu, et toute la concurrence d'entrées/sorties est disponible. Contrairement à la Queue, une task dispose d'un statut, d'une progression et d'un résultat intégrés. Le planificateur déclenche des traitements à heure fixe, selon une expression cron.
Écrire des tasks
Un worker de tasks est démarré une fois puis réutilisé d'un job à l'autre. Déclarez vos tasks avec
defineTask, puis démarrez le worker avec startTaskWorker, tous deux importés depuis
@bext-stack/framework/task-worker :
import { defineTask, startTaskWorker } from "@bext-stack/framework/task-worker";
defineTask("generate-report", async (ctx, payload) => {
ctx.log("starting", payload);
const rows = await ctx.db.all("SELECT * FROM sales WHERE month = ?", [payload.month]);
await ctx.progress({ pct: 50 });
const url = await buildPdf(rows);
await ctx.kv.set(`report:${ctx.jobId}`, { url });
return { url }; // becomes the job's `result`
});
startTaskWorker();
Appelez defineTask au premier niveau du module, avant startTaskWorker(). Ce fichier est un
point d'entrée de worker, pas une route : il s'exécute dans son propre processus de longue durée,
en dehors du rendu des pages. La plateforme enregistre le point d'entrée du worker de votre
application et le démarre à la demande ; l'exécution de tasks doit être activée pour votre
application.
Le ctx d'une task
ctx contient l'intégralité de BextSdk (voir la Présentation du SDK) et des
champs propres aux tasks :
Sur ctx |
Rôle |
|---|---|
ctx.kv, ctx.db, ctx.queue, … |
Tous les namespaces du SDK. |
ctx.appId |
L'identifiant de votre application. |
ctx.jobId |
L'identifiant de ce job, stable même si le job est rejoué. |
ctx.signal |
Un AbortSignal, déclenché quand le délai du job est dépassé. Passez-le à fetch et vérifiez-le dans vos boucles. |
ctx.progress(data) |
Publier une progression (toute valeur JSON), visible dans le statut du job. Ne lève jamais d'erreur. |
ctx.log(...) |
Écrire une ligne de journal depuis la task. |
ctx.sdk |
Le même client SDK, sous forme d'objet unique. |
La valeur retournée par le handler devient le result du job (null si le handler ne retourne
rien). Une erreur levée passe le job au statut error avec son message.
La livraison est at-least-once : après une interruption, un job peut être rejoué avec le même
ctx.jobId. Utilisez ctx.jobId comme clé d'idempotence avant tout effet externe (paiement,
e-mail, appel à une API tierce).
Lancer une task et suivre son statut
Une exécution de task prend les paramètres suivants :
| Paramètre | Obligatoire | Rôle |
|---|---|---|
task |
oui | Nom déclaré avec defineTask |
payload |
non | Donnée passée en second argument au handler |
timeout_secs |
non | Délai maximal, 300 secondes par défaut et 1800 au plus ; au-delà, ctx.signal est déclenché |
trigger |
non | Libellé libre qui indique l'origine de l'exécution ("api" par défaut, "cron" pour les exécutions planifiées) |
Le client du framework n'a pas de méthode pour lancer une exécution : elles sont lancées par la
plateforme, par exemple par une planification. Le lancement répond
immédiatement avec { jobId, status: "queued" }. Le travail se poursuit en arrière-plan ; on peut
ensuite lire le statut du job, lister les jobs récents (50 par défaut, 500 au plus) ou annuler un
job.
Le statut d'un job a cette forme :
{
"id": "…", "task": "generate-report", "status": "…", "progress": {},
"result": {}, "error": null, "trigger": "…",
"createdAt": "…", "updatedAt": "…", "finishedAt": "…"
}
status vaut queued, running, success, error, timeout ou canceled. progress reprend
la dernière valeur passée à ctx.progress, result la valeur retournée par le handler, error le
message d'erreur en cas d'échec.
Seul un job queued ou running peut être annulé. L'annulation passe le job à canceled sans
interrompre un handler déjà en cours ni déclencher ctx.signal : le handler va jusqu'au bout,
mais son résultat est ignoré et le statut reste canceled. Les jobs terminés sont conservés
7 jours, puis supprimés.
Le planificateur
Le planificateur enregistre des traitements récurrents. Comme pour les handlers de queue, le client du framework n'a pas d'appel pour enregistrer une planification : elles sont mises en place pour votre application par la plateforme. Une planification se définit par :
| Champ | Rôle |
|---|---|
name |
Nom unique de la planification ; un nom déjà utilisé par une autre application est refusé |
schedule (ou cron) |
Expression cron, évaluée en UTC : 0 3 * * * se déclenche à 03:00 UTC chaque jour |
task ou handler_url |
Ce qui est déclenché : une task déclarée avec defineTask, ou un POST vers une URL de votre application |
payload |
Donnée passée à la task à chaque déclenchement (planifications de task uniquement) |
timeout_secs |
Délai maximal d'une exécution de task, 300 secondes par défaut et 1800 au plus |
enabled |
Active ou suspend la planification (active par défaut) |
Les expressions cron comptent 5 champs, ou 6 avec les secondes en tête, et acceptent les raccourcis
@hourly, @daily (ou @midnight), @weekly, @monthly et @yearly (ou @annually). Pour
le jour de la semaine, 0 et 7 désignent tous deux le dimanche. Les expressions sont validées à
l'enregistrement :
une expression invalide est refusée. Enregistrer à nouveau un nom met à jour la planification. Les
planifications peuvent être listées et annulées par leur nom.
Une planification HTTP envoie ce corps en POST à son handler_url, où scheduled_for est un
horodatage Unix en secondes :
{ "name": "nightly-report", "app_id": "<app-id>", "scheduled_for": 1767236400 }
Le handler_url suit la même règle que les handlers de queue : une URL sur le domaine de votre
application, parmi les URL de rappel que la plateforme a autorisées pour elle.
Faites passer tous vos traitements récurrents par le planificateur : il est limité à votre application, valide les expressions cron, et chaque planification reste visible dans la liste. Voir Jobs planifiés.
Tasks, queue ou planificateur
| Utilisez… | Quand |
|---|---|
| Tasks | Un traitement long que vous voulez suivre : statut, progression et résultat. Pas de délai de rendu, toute la concurrence d'entrées/sorties. |
| Queue | Une livraison en volume, sans retour, vers un handler HTTP. At-least-once, pas de résultat stocké. |
| Planificateur | Un traitement déclenché par l'heure. Lance une task ou appelle un handler HTTP selon une expression cron. |
Et ensuite
| Page | Ce qu'elle couvre |
|---|---|
| Queue | Livraison sans retour et handlers |
| KV Store | Conserver des résultats et des enregistrements de job |
| Jobs planifiés | Les traitements planifiés sur la plateforme |