Tâches et traitements différés
Abonnez une extension aux événements métier et planifiez ses effets avec des reprises explicites.
Sur cette page
File PostgreSQL
Le serveur exécute les publications planifiées, l’outbox e-mail, les tâches récurrentes et les jobs déclarés par les plugins. Les jobs utilisent baux d’exécution, tentatives, délais de reprise et clés de déduplication facultatives. pnpm cms jobs:run lance un passage lorsque le serveur est arrêté.
jobs: [{
name: "cleanup",
async handler(_payload, context) {
await context.database.query(
"DELETE FROM example_records WHERE expires_at < now()",
);
},
}],
async activate(context) {
await context.services.jobs?.schedule("cleanup", {}, { intervalSeconds: 3600 });
}Au moins une fois
Une interruption après un effet réseau peut provoquer sa répétition. Préparez des handlers idempotents et des identifiants métier stables. Un plugin inactif ne doit plus exécuter ses contributions. Ses données restent conservées ; un mécanisme métier peut annuler ses demandes en attente, comme les alertes de connexion de Security.
Le cache Redis est un provider optionnel, pas le moteur de queue. La capture d’e-mails conserve des fichiers locaux ; SMTP exige la sélection explicite de son fournisseur pour délivrer à l’extérieur. Les sélecteurs historiques restent disponibles. Les extensions métier continuent d’utiliser email.enqueue sans connaître le transport.
Événements métier durables
PluginDefinition.events accepte user.created, auth.login, plugin.updated, content.published, backup.completed et job.failed. L’opération inscrit une tâche par extension active abonnée, dans sa transaction. context.event fournit un identifiant stable et occurredAt ; utilisez cet identifiant pour dédupliquer vos effets. content.published correspond au passage à l’état publié, pas à chaque correction. job.failed correspond à un échec terminal, pas à chaque tentative.
Les jobs et événements associés à un acteur utilisateur conservent son identité, sa version et un plafond de permissions, y compris les scopes Bearer. La reprise les intersecte avec ses droits actuels. Une action déjà mise en file n’est pas annulée par la seule révocation du token ; un changement de compte ou de droits peut bloquer sa reprise. auth.login est un événement système explicite avec context.user nul : son payload contient l’identifiant et la version du compte, que le destinataire doit revérifier. Les tâches historiques sans snapshot gardent leur comportement système et doivent être auditées lors d’une migration.
Les hooks transactionnels restent distincts de cette livraison au moins une fois. Les webhooks du CMS fournissent le transport sortant signé ; une extension peut déclarer ses propres événements et les publier dans l’outbox. plugin:command reste une commande opérateur, sans devenir automatiquement un job réessayable. Le SDK ne fournit pas de bus universel event.on.
Alertes de connexion de Security
Security 0.1.2 consomme auth.login, émis uniquement lors de la création d’une session après authentification complète, MFA comprise. Le payload se limite à { id, version } ; il ne contient ni adresse e-mail, ni IP, ni jeton, ni secret MFA. Un SAVEPOINT isole son insertion : un échec de notification n’annule pas la session valide et produit seulement le diagnostic générique auth.login_notification_unavailable. Aucun transport e-mail n’est appelé pendant la connexion.
La migration 2 crée bracten_security_login_alerts, sans abonner personne. POST /api/v1/extensions/bracten.security/endpoints/login_alerts accepte uniquement { enabled, locale, version }, avec locale égal à fr ou en. La session, l’origine exacte, le CSRF, la permission bracten.security.manage et la version de préférence sont vérifiés. Le compte courant est le seul destinataire possible ; son adresse est relue côté serveur. Le catalogue FR/EN du formulaire et des e-mails appartient au module signé, dans extensions/official/security/src/messages.ts. La langue d’e-mail ne change ni la préférence d’interface ni site.language.
Le handler relit le compte actif, sa version et le consentement, puis appelle email.enqueue dans sa transaction. Le verrou de préférence et la date du dernier événement traité écartent les doublons concurrents, les événements rejoués et ceux antérieurs à l’activation. La file accepte au maximum une nouvelle alerte toutes les quinze minutes, et une seule alerte encore en attente ou en cours par compte. Désactiver puis réactiver la préférence ne remet pas ce délai à zéro. La livraison reste au moins une fois ; le Message-ID stable ne garantit pas une réception unique par SMTP.
Retirer le consentement, changer la langue d’e-mail, modifier le compte via le service utilisateurs ou désactiver Security annule uniquement ses jobs email.deliver non terminés, par lots bornés. Security supprime aussi ses événements auth.login en attente lors de sa désactivation. Un job déjà réclamé est retiré pour que la mise à jour conditionnelle du worker ne recrée aucune tentative, mais son transport peut avoir commencé et ne peut pas être rappelé. L’annulation conserve une date et une trace d’audit sans coordonnées ni contenu privé ; les préférences survivent à la désactivation et suivent les sauvegardes de la base.
Le transport capture écrit un fichier local privé et ne contacte aucun destinataire. La recette décrite dans docs/security-login-alerts.md couvre le consentement, FR/EN, MFA, la concurrence, l’annulation pendant un traitement et la conservation après redémarrage, avec capture uniquement. Elle ne prouve aucune délivrabilité SMTP externe. Les libellés historiques de Security et les e-mails MFA/récupération du noyau restent en français.
Observer les services
L’écran Santé expose le planificateur, des métriques bornées du processus et l’état des reporters. Les statuts et durées des jobs sont observés après commit. services.observability ne donne accès qu’à l’espace du plugin ; aucun rapport n’est envoyé à l’extérieur sans reporter configuré avec consentement. Les extensions SMTP, S3 et Redis enregistrent leurs factories et conservent leurs diagnostics sur le fournisseur sélectionné. Redis se connecte à l’initialisation, S3 à l’opération et SMTP à la livraison du job ; un démarrage réussi ne prouve donc pas l’accès au bucket ou la livraison d’un e-mail.
La recette de tests/integration/official-providers.test.mjs compile les trois packages hors du dépôt via le SDK public. Elle utilise le vrai client AWS SDK face à un serveur S3 protocolaire local, un vrai Redis local et un serveur SMTP TLS local avec refus d’un certificat non approuvé. Les preuves couvrent sélection, cycle de vie, absence de repli, médias, sauvegardes et restaurations. Elles ne qualifient ni AWS/MinIO distant, ni un cluster Redis, ni la délivrabilité SMTP externe. La capture e-mail reste un contrôle distinct sans envoi réseau.