Si jamais vous devez implémenter un système de planification de tâches, sachez que l’Azure Service Bus de Microsoft offre nativement une fonctionnalité de planification de messages sur laquelle on peut se baser pour déclencher des traitements différés. Nous avons nous-même utilisé ce mécanisme pour développer une application capable de planifier des envois de mails ou de SMS, et de les envoyer à la date et l’heure prévues.

Solution de planification historique : SQL et batchs

Jusqu’alors, nous utilisions un système de planification développé en interne qui repose sur :

  • Une table de traitements dans une base de données SQL Server. Chaque ligne de la table « Traitement » contient les paramètres de la tâche à réaliser ainsi que la date et l’heure d’exécution souhaitées.
  • Des batchs, implémentés sous la forme d’applications console, déclenchés périodiquement à l’aide du planificateur de tâches de Windows (tous les quarts d’heure par exemple). Ces batchs requêtent la table « Traitement » pour récupérer les lignes qui n’ont pas encore été traitées et dont la date et l’heure de programmation sont passées, puis exécutent les tâches correspondantes.

Cette solution fonctionne, mais elle présente quelques inconvénients :

  • Il s’agit d’un logiciel interne, et donc d’une application supplémentaire (avec son infrastructure) à développer, monitorer et maintenir.
  • Un manque de réactivité : si un traitement est planifié pour 10h01 mais que le batch responsable de l’exécuter ne se lance que tous les quarts d’heure, le traitement sera réalisé au plus tôt à 10h15, soit 14 minutes après l’heure prévue.
  • Une difficulté à gérer la montée en charge (l’augmentation du nombre de traitements à effectuer) : chaque batch requête la table des traitements et les exécute l’un après l’autre. Il serait possible de paralléliser leur exécution à l’aide de multithreading ou en les distribuant à plusieurs applications, mais ce n’est pas trivial.

Nouveau système de planification avec le Service bus

Partant de ce constat, nous avons décidé de changer d’approche pour implémenter notre application d’envoi de mails et SMS, en nous appuyant sur la fonctionnalité de planification de messages de l’Azure Service Bus plutôt que sur notre système historique. Voici le principe général :

  • L’infrastructure nécessaire est une simple file de messages ou un topic d’un service bus.
  • L’application en charge de planifier une tâche écrit un message dans la queue ou le topic, en précisant sa date d’exécution souhaitée à l’aide de la propriété ScheduledEnqueueTimeUtc. Le message deviendra disponible et pourra donc être consommé à la date renseignée, en attendant ce moment il sera conservé dans la queue ou le topic.
  • L’application responsable d’exécuter la tâche écoute la file de messages ou est abonnée au topic, et peut donc commencer son travail dès qu’un message devient disponible. Cette application peut être implémentée sous la forme d’une Azure Function, qui peut se déclencher lors de la détection de messages dans une file ou un topic (voir l’article Azure Service Bus bindings for Azure functions).

Un exemple de code illustrant la planification d’un message :

Et à l’autre bout de la file, un exemple d’Azure Function déclenchée à chaque fois qu’un message devient disponible :

 

Comparatif des solutions

Les deux schémas ci-dessous illustrent la différence de fonctionnement des deux solutions. Dans le cas du système historique, c’est à l’application responsable d’envoyer les mails (le batch), d’aller chercher elle-même les informations dans une table SQL, les mails sont ensuite envoyés séquentiellement.

Solution historique utilisant une table SQL et un batch

Avec le nouveau système, les messages sont placés dans une file de messages avec une date de planification, le service bus les rendra disponible à ce moment-là, chaque message disponible déclenchera alors l’instanciation du consommateur qui enverra le mail correspondant. Si plusieurs instances du consommateur sont déployées, plusieurs messages disponibles en même temps dans la file seront traités en parallèle.

Nouvelle solution basée sur une file de messages

Cette architecture permet de régler de façon élégante les problèmes posés par notre solution historique :

  • Au niveau infrastructure, il n’est plus nécessaire de gérer une base de données et une table de traitements, une queue ou un topic de service bus suffisent à présent.
  • Nous n’avons plus besoin de gérer des batchs récurrents pour détecter que des tâches doivent être exécutées : c’est désormais la simple présence d’un message dans la queue ou le topic qui indique qu’un travail est en attente.
  • En déclenchant l’application consommatrice dès qu’un message devient disponible, on permet une meilleure réactivité : chaque tâche est traitée au plus tôt après sa date planifiée.

Remarque :

Nous avons utilisé l’Azure Service Bus pour planifier des messages, mais ce mécanisme est aussi disponible dans les files de type Azure Storage. Cependant il est plus restreint : les messages ne peuvent pas rester plus de 7 jours dans une file (Files d’attente Azure et files d’attente Service Bus : comparaison et différences).

 

Références :

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *