web-dev-qa-db-fra.com

Longue exécution REST API avec files d'attente

Nous implémentons une API REST), qui lancera plusieurs tâches principales de longue durée. J'ai lu le livre de recettes des services Web RESTful et il est recommandé de renvoyer HTTP 202/Accepted avec un emplacement de contenu. en-tête pointant vers la tâche en cours de traitement (par exemple, http://www.example.org/orders/tasks/1234 ) et demandez au client d'interroger cet URI pour obtenir une mise à jour de la tâche à exécution longue.

L’idée est que l’API REST publie immédiatement un message dans une file d’attente, avec un rôle d’agent de travail en arrière-plan prenant le message dans la file d’attente et créant plusieurs tâches d’arrière-plan, en utilisant également des files d’attente. Le problème Je vois avec cette approche comment attribuer un identifiant unique à la tâche et laisser ensuite le client en demander l’état en émettant un GET sur l’URI Content-Location.

Si l'API REST est immédiatement publiée dans une file d'attente, elle peut générer un GUID et l'attacher en tant qu'attribut dans le message ajouté à la file d'attente, mais extraire le statut de la demande devient difficile.

Une autre option serait que l’API REST ajoute immédiatement une entrée à la base de données (disons une commande, avec un nouvel identifiant de commande)), avec un statut initial, puis un message ensuite. file d'attente pour lancer les tâches d'arrière-plan, qui mettront ensuite à jour cet enregistrement de base de données.L'API renverra ce nouvel ID de commande dans l'URI de l'en-tête Content-Location, à utiliser par le client lors du contrôle de l'état de la tâche.

D'une certaine manière, ajouter d'abord l'entrée de la base de données, puis ajouter le message à la file d'attente semble à l'envers, mais le seul ajout de la demande à la file d'attente complique le suivi des progrès.

Quelle serait l'approche recommandée?

Merci beaucoup pour vos idées.

52
user2079172

Je suppose que votre système ressemble à ce qui suit. Vous disposez d'un service REST, qui reçoit les demandes du client. Il convertit les requêtes en commandes que la logique métier peut comprendre. Vous mettez ces commandes dans une file d'attente. Vous avez un ou plusieurs travailleurs qui peuvent traiter et supprimer ces commandes de la file d'attente et envoyer les résultats au service REST, qui peut répondre au client.

Votre problème est que, du fait de vos longues tâches, le délai de connexion du client expire, vous ne pouvez donc pas envoyer de réponse. Vous pouvez donc envoyer un 202 accepté après avoir placé les commandes dans la file d'attente et ajouté un lien d'interrogation afin que le client puisse interroger les modifications. Vos tâches ont plusieurs sous-tâches, donc il y a des progrès, pas seulement des changements de statut en attente et complets.

  1. Si vous souhaitez vous en tenir à l'interrogation, vous devez créer une nouvelle ressource REST, qui contient l'état actuel et la progression de la tâche de longue durée. Cela signifie que vous devez stocker ces informations dans une base de données. Par conséquent, le service REST pourra répondre à des demandes telles que GET /tasks/23461/status. Cela signifie que votre agent doit mettre à jour la base de données lorsqu'elle termine une sous-tâche ou l'intégralité de la tâche.
  2. Si votre service REST est exécuté en tant que démon, vous pouvez le notifier par progression. Par conséquent, l'enregistrement du statut de la tâche dans la base de données ne sera pas de la responsabilité du travailleur. Ce type de service REST peut également stocker les informations dans la mémoire.
  3. Si vous décidez d'utiliser des websockets pour notifier le client, vous pouvez créer un service de notification. Par REST, vous devez répondre avec un identifiant de tâche. Après cela, vous renvoyez cet identifiant de tâche sur la connexion websocket afin que le service de notification sache quelle connexion websocket a souscrit aux événements d'une tâche donnée. Après cela, vous n’avez plus besoin du service REST, vous pouvez envoyer la progression via la connexion websocket tant que le client ne ferme pas la connexion.
  4. Vous pouvez combiner ces solutions de la manière suivante. Vous laissez votre service REST créer une ressource de tâche pour pouvoir accéder à la progression à l'aide d'un lien d'interrogation. Après cela, vous renvoyez un identifiant avec 202 que vous renvoyez via la connexion websockets. Vous pouvez donc utiliser un service de notification pour informer le client. Par la suite, votre agent notifiera le service REST, qui créera un lien du type GET /tasks/23461/status Et l'enverra au client via le service de notification. Après cela, le client peut utiliser le lien pour mettre à jour son statut.

Je pense que le dernier est la meilleure solution si votre service REST fonctionne comme un démon. C’est parce que vous pouvez déplacer la responsabilité de la notification vers un service de notification dédié, qui peut utiliser des websockets, des scrutations, des SSE, tout ce que vous voulez. Il peut s'effondrer sans tuer le service REST. Le service REST restera donc stable et rapide. Si vous renvoyez également un lien de mise à jour manuelle avec le 202, le client peut effectuer une mise à jour manuelle (en supposant un client contrôlé par un utilisateur). Vous aurez ainsi une dégradation progressive si le service de notification n'est pas disponible. Vous n'avez pas besoin de maintenir le service de notification, car il ne saura rien des tâches, il se contentera d'envoyer des données aux clients. Votre travailleur n'aura pas besoin de savoir comment envoyer des notifications et créer des hyperliens. Il sera également plus facile de gérer le code client car ce sera presque un client REST pur. La seule fonctionnalité supplémentaire sera l'abonnement aux liens de notification, qui ne change pas souvent.

54
inf3rno