File d'attente
La queue livre une charge utile (payload) à un handler de votre application. Elle est at-least-once et fire-and-forget : elle ne stocke aucun résultat et n'expose aucun statut par message. Vous mettez un message en file, puis la plateforme appelle le handler HTTP enregistré pour cette queue.
Mettre en file
import { createSdk } from "@bext-stack/framework/sdk";
const sdk = createSdk("<app-id>");
const id = await sdk.queue.push("emails", { to: "a@b.com" });
Appelez-la côté serveur (loader, action, route.ts ou tâche). push(queue, payload, delaySecs?)
retourne l'identifiant du message et lève une erreur si la plateforme refuse la mise en file. Une
charge utile qui n'est pas une chaîne est sérialisée avec JSON.stringify ; une chaîne est
envoyée telle quelle.
Le troisième argument, delaySecs, retarde la livraison : le message n'est remis qu'après ce
délai, en secondes entières (une valeur non entière est ignorée et le message part tout de
suite). Pour un traitement récurrent, utilisez plutôt une planification.
Enregistrer un handler
Chaque queue est traitée par un handler : une URL HTTP de votre application que la plateforme appelle pour chaque message. Le client du framework n'a pas d'appel pour en enregistrer un : les handlers HTTP sont activés pour votre application par la plateforme, avec les réglages suivants :
| Réglage | Obligatoire | Rôle |
|---|---|---|
queue |
oui | Nom de la queue à traiter |
handler_url |
oui | URL du handler, par exemple https://<app>.inklura.fr/api/queue/emails |
concurrency |
non | Nombre maximal de livraisons simultanées (1 par défaut, 1 au minimum) |
visibility_timeout_secs |
non | Durée qu'une livraison peut prendre avant d'être retentée (30 par défaut) |
Le handler_url doit être une URL http ou https sur le domaine de votre application (un nom de
domaine, sans identifiants ni fragment #), parmi les URL de rappel que la plateforme a autorisées
pour elle. La plateforme attend la réponse de votre handler jusqu'à
visibility_timeout_secs, avec un minimum de 30 secondes et un maximum de 15 minutes : réglez-le
au-dessus de la durée d'exécution la plus longue de votre handler, sinon une livraison lente mais
réussie est retentée.
Contrat du handler
La plateforme envoie ce corps en POST à votre handler_url :
{ "id": "<message-id>", "queue": "emails", "payload": { }, "attempts": 0 }
attempts compte les livraisons précédentes : 0 à la première. Toute livraison compte, y
compris celles qui finissent en délai dépassé.
Avec sdk.queue.push, payload arrive sous forme de chaîne JSON (la charge utile est
sérialisée avant l'envoi) : décodez-la avec JSON.parse, comme dans l'exemple plus bas.
Le statut de réponse de votre handler décide de la suite :
| Réponse | Effet |
|---|---|
2xx |
ack : le message est traité |
408, 429, 5xx |
retry : relivré après le délai Retry-After que vous envoyez (nombre entier de secondes, au moins 1), 30 secondes par défaut, plafonné à visibility_timeout_secs |
| tout autre statut | dead-letter : le message part dans la queue morte |
| pas de réponse (injoignable, délai dépassé) | retry une fois visibility_timeout_secs écoulé |
Un message part en dead-letter après 5 tentatives de livraison. Un Retry-After sous forme de
date HTTP n'est pas pris en compte : le délai par défaut s'applique.
Écrivez le handler sous forme de route.ts :
export async function POST(request: Request) {
const { id, payload, attempts } = await request.json();
const data = typeof payload === "string" ? JSON.parse(payload) : payload;
try {
await sendEmail(data);
return new Response(null, { status: 200 }); // ack
} catch (e) {
return new Response(String(e), { status: 500 }); // retry
}
}
Sémantique à prévoir
- At-least-once : un handler peut recevoir le même message plusieurs fois. Rendez vos handlers
idempotents, par exemple en dédupliquant sur
id. - Fire-and-forget : la mise en file retourne un
id, rien de plus. Il n'existe pas de moyen intégré de savoir si le message X a réussi. - Dead-letter : les messages qui épuisent leurs tentatives, ou dont le handler renvoie un statut non réessayable, arrivent dans la queue morte. Ils y restent avec leur charge utile et peuvent être listés, remis en file (tous ou un par un, avec un compteur de tentatives remis à zéro) ou purgés.
- Entrée non fiable : le handler est une route de votre application comme une autre. Traitez le corps reçu comme une entrée externe et, avant une action irréversible, revérifiez l'état que vous avez stocké plutôt que de vous fier à la seule charge utile.
Ajouter un enregistrement de job pour suivre un statut
Comme la queue ne stocke pas de résultat, une application qui a besoin de l'issue conserve un
enregistrement de job durable en KV : des clés comme job:<id> que le handler met à
jour (queued → running → complete / fail).
Queue ou tasks
Pour un traitement long avec statut et progression intégrés, utilisez plutôt les Tasks. La queue convient à une livraison en volume, sans retour, vers un handler HTTP.
Et ensuite
| Page | Ce qu'elle couvre |
|---|---|
| Tasks & Planificateur | Traitements longs avec statut et progression, planification |
| KV Store | Le motif d'enregistrement de job durable |
| Queue Workers | Exploiter et observer les handlers |