REST est-il uniquement limité à un contrôle de concurrence optimiste?

9

Le contexte

En raison de l'apatridie du style architectural REST, chaque demande est complètement isolée, ce qui conduit le serveur à ne jamais stocker d'informations sur le client.

Ainsi, le contrôle d'accès concurrentiel pessimiste ne convient pas car il nécessiterait que le magasin de serveurs dont le client obtient le verrou sur une ressource. Un contrôle de concurrence optimiste est ensuite utilisé, à l'aide de l'en- Etagtête. (btw, comme je l'ai demandé là /programming/30080634/concurrency-in-a-rest-api )

Problème

Le principal problème avec un mécanisme de contrôle de concurrence optimiste est que vous autorisez tout le temps, tous les clients, à effectuer toutes les opérations.

Et j'aimerais éviter cela sans enfreindre le principe de l'apatridie de REST. Je veux dire que tous les clients ne peuvent effectuer aucune opération à tout moment.

Question

Dans mon esprit, cela serait possible avec un mécanisme de contrôle d'accès concurrentiel semi-optimiste , comme celui-ci:

  • Les clients peuvent demander un jeton
  • Un seul jeton peut être généré et a une durée de validité limitée
  • Pour effectuer des opérations sur les ressources (telles que POST ou PUT ), le client doit donner ce jeton dans le corps (ou en-tête?) De la demande. Le client qui n'a pas le jeton ne peut pas effectuer ces opérations.

Il est très similaire au contrôle de concurrence optimiste, sauf qu'un seul client peut effectuer certaines opérations (celui qui a obtenu le jeton) ... à l'opposé de "tous les clients peuvent effectuer toutes les opérations".

Ce mécanisme est-il compatible avec un style architectural REST? Brise-t-il une de ses contraintes? Je pensais poser des questions sur SO, mais cela semble plutôt une question de haut niveau, liée à la conception de logiciels.

AilurusFulgens
la source
1
C'est assez simple, en fait: vous devez modéliser Transactionexplicitement une ressource.
Jörg W Mittag
Qu'est-ce que ça change? Pas sûr de comprendre votre commentaire. Je ne fais pas de contrôle de concurrence pour la transaction, mais plutôt pour dire au client "ok maintenant, vous êtes absolument sûr que personne ne changera la ressource" (car il a obtenu un jeton unique).
AilurusFulgens
1
Quelle est la différence? D'un côté, vous utilisez l'Etag pour vérifier qui est autorisé à mettre à jour la version "actuelle"; s'il se heurte, vous devez mettre à jour votre version et faire la mise à jour après cela. De l'autre côté, vous avez votre mécanisme de "verrouillage": l'un est autorisé, les autres doivent attendre. Sonne à peu près la même chose. L'inconvénient de la deuxième approche: 2 demandes - 1 pour le verrou et 1 pour la mise à jour. Dans un cas optimal, vous n'avez qu'une seule mise à jour via l'approche Etag.
Thomas Junk
Eh bien, de manière générale sur le contrôle des accès simultanés ... le second qui a "perdu la course" devra toujours attendre (juste pour des raisons différentes, je suis d'accord avec cela). Différence avec Etag? Avec Etagvous n'êtes jamais sûr que vos opérations seront terminées, vous pourriez avoir une situation où vous n'effectuerez jamais aucune opération. Avec une serrure, vous êtes sûr au moins d'effectuer votre opération. Donc, avoir un simple verrou est juste un milieu entre un environnement où des "conflits élevés" et des "conflits rares" peuvent se produire.
AilurusFulgens

Réponses:

3

Vous ne devez jamais (comme jamais jamais) verrouiller une ressource en attendant une interaction utilisateur.

À un moment donné, certains de vos utilisateurs décolleront pour un long week-end, laissant certains enregistrements vitaux verrouillés.

Ah mais vous ne laisserez pas cela se produire parce que vous avez un schéma intelligent de résolution de time out / deadlock; puis à un moment donné, cela ira horriblement mal et un utilisateur qui a reçu un joli message "votre widget a été commandé" criera au service d'assistance pour savoir pourquoi son widget n'a pas été livré.

La plupart des gens peuvent gérer le message "Désolé, un autre utilisateur vient de commander cette pièce".

James Anderson
la source
Vous l'avez bien expliqué. Bien que je ne sois pas complètement convaincu par votre première phrase: à un moment donné, vous garantissez que personne d'autre que vous ne peut exécuter une commande. Mais bon, votre dernière phrase est un bon résumé, dans 99% des cas c'est le cas.
AilurusFulgens
1
Si vous devez verrouiller un enregistrement pour un utilisateur particulier, faites-le au niveau de l'application. Soit un simple attribut "LockedBy", soit un mécanisme de gestion des versions et de workflow plus sophistiqué.
James Anderson
Qu'entendez-vous par «au niveau de l'application»? Si vous ajoutez un attribut "LockedBy" sur votre ressource, vous stockez des informations sur le client sur votre serveur. Ou peut-être que je n'ai pas compris votre commentaire. Si vous pouvez fournir des détails, ce serait formidable!
AilurusFulgens
1
@AilurusFulgens - Vous ajoutez un attribut LockedBy (et éventuellement un horodatage LockedOn) à votre base de données. Dans votre code d'application, vous définissez le nom d'utilisateur et l'heure à chaque fois que le client démarre une interaction de mise à jour. Vous le désactivez lorsque le client a terminé - vous devez ensuite élaborer des règles commerciales pour résoudre les conflits et les délais d'expiration, etc.
James Anderson
2

L'utilisation de jetons est très courante dans les API, ces jetons sont généralement envoyés en tant qu'en-tête et ont un cycle de vie clair. Pensez par exemple à OAuth.

Quel que soit votre langage de programmation ou votre infrastructure, les API REST sont similaires.

Je peux penser à plusieurs scénarios où vous souhaitez limiter la concurrence, deux d'entre eux sont:

  1. Plusieurs clients mettant à jour les mêmes ressources comme une ligne de base de données. Par exemple: deux demandes simultanées, l'une supprime un enregistrement et l'autre essaie de mettre à jour le même enregistrement. En fonction de votre base de données et de la façon dont vous l'avez configurée, vous pouvez obtenir un verrou sur les enregistrements ou une opération non valide car les données seront différentes ou n'existeront pas.

  2. Un super utilisateur ou administrateur effectuant des actions spéciales avec l'API.


Que faire dans ces cas?

  1. Utilisez des transactions dans la base de données, des singletons, des verrous et des mécanismes similaires pour synchroniser l'accès aux ressources.

  2. Le jeton pourrait fonctionner, je pense que ce sera mieux si vous ne stockez pas d'informations sur le client, juste sur le jeton lui-même. En une seule étape, vous pouvez valider l'utilisateur et attribuer le jeton. Ensuite, validez simplement que le jeton est vivant et qu'il est valide. Utilisez un jeton qui peut être déchiffré pour obtenir des informations supplémentaires. Vous pouvez stocker s'il s'agit d'un jeton spécial et ne l'autoriser qu'à la fois. De cette façon, vous validez le jeton, pas l'utilisateur.

J'espère que ça aide.

Pablo Granados
la source
Oui, je m'attendais à une réponse sur la similitude d'un jeton et du mécanisme OAuth. Bien que le dernier soit dédié à l'authentification. Je n'ai pas compris le point de votre scénario 1. La partie délicate pour gérer la concurrence dans une API REST est de garder la contrainte d'apatridie ... ce qui signifie que le serveur ne stocke pas d'informations sur le client. Votre scénario 2 est exactement ce que je fais actuellement! :)
AilurusFulgens
Ai-je répondu à votre question?
Pablo Granados
Non désolé. J'ai voté en faveur de votre réponse, car elle donne un bon aperçu du problème, mais malheureusement, imo, ce n'est pas vraiment le résoudre.
AilurusFulgens
0

REST seul est vraiment trop primitif, vraiment. Vous pouvez commencer avec REST, mais à terme, votre application riche aura besoin de requêtes avec jointures et de mises à jour avec transactions. Chaque développeur tentant d'ajouter ces éléments par lui-même serait sujet aux erreurs et incohérent. Heureusement, il existe une nouvelle norme appelée OData qui fait exactement cela. Il se superpose à REST et fournit (1) un langage de requête qui permet des jointures simples en utilisant des propriétés de navigation (sans avoir à exposer des clés étrangères), et, (2) un traitement par lots qui inclut des ensembles de modifications atomiques.

Voir ici pour (1) https://stackoverflow.com/a/3921423/471129 , et,

Voir ici et pour (2) https://stackoverflow.com/a/21939972/471129

Erik Eidt
la source