Côté serveur verrouillage optimiste dans une application RESTful: le traitement des demandes asynchrones du même client

voix
1

Je travaille sur un projet qui est en transition de la preuve de concept à quelque chose digne d'un projet pilote. L'une des principales améliorations de cette phase de développement est de se éloigner du mécanisme de « persistance » actuelle, qui utilise une table de hachage tenue en mémoire et sous-évaluées périodiquement dans un fichier, dans une base de données plus traditionnelle back-end.

L'application elle - même est conçu avec RESTful principes à l' esprit. Il utilise Jersey pour fournir un accès aux ressources et jQuery pour présenter ces ressources à l'utilisateur et permettre des interactions de base (créer, mettre à jour, supprimer). Assez simple.

Je l'ai utilisé JPA et Hibernate avec succès dans le passé pour état persistant côté serveur dans une base de données relationnelle, il semblait un choix naturel dans ce cas. Avec quelques modifications mineures aux entités du modèle, je suis en mesure d'obtenir lecture de base, créer et supprimer des opérations de travail dans un délai raisonnable. Cependant, l'opération de mise à jour a été plus difficile.

La partie de l'application côté client envoie automatiquement les modifications au serveur quelques secondes après que l'utilisateur modifie la ressource. De plus, il y a un bouton « Enregistrer et fermer » que l'utilisateur peut appuyer pour envoyer immédiatement la dernière version de la ressource sur le serveur avant de retourner à la page d'accueil.

Mon premier problème était de savoir comment mettre à jour l'entité gérée à partir de la base de données avec l'objet non géré provenant du client. Étant donné que les données envoyées au client omet délibérément les clés de la base de données, c'était un peu pénible car il est descendu explicitement « la fusion » des éléments de l'objet non géré dans l'objet Mise en veille prolongée. Ce n'est pas ma question, mais si quelqu'un sait d'une façon élégante de le faire, je serais très intéressé d'entendre parler.

Mon second problème, et l'objet de ce post, se produit lorsque j'appuie sur le bouton « Enregistrer et fermer » dans le même temps que l'opération de sauvegarde automatique je l'ai mentionné plus tôt est en cours. Plus souvent qu'autrement, je reçois une exception de verrouillage optimiste. En effet, la seconde opération de mise à jour est en cours de traitement dans un thread séparé tandis que la première est encore en cours de traitement.

La ressource a un horodatage « mis à jour » qui est défini chaque fois qu'une mise à jour est traitée, donc une mise à jour de la base de données est à peu près garantie à chaque fois, même si rien n'a changé. Cela en soi est probablement un problème, mais même après je résoudre ce problème, il y a encore une « fenêtre d'opportunité » où l'utilisateur pourrait faire une modification et l'envoyer au serveur lors d'une sauvegarde automatique est en cours, ce qui déclenche le même problème .

L'approche la plus simple que je peux penser à résoudre ce problème est de Retravailler certains Javascript côté client pour assurer qu'il n'y a jamais qu'un seul remarquable « mise à jour » opération de ce client à tout moment. (Notez que si un autre client arrive à mettre à jour la même ressource en même temps, une exception de verrouillage optimiste est parfaitement bien.) Cependant, je crains que forcer cette limitation sur le client peut être écarter de l'esprit de repos. Est - il raisonnable d'attendre un client donné d'avoir plus d'une exceptionnelle « mise à jour » (PUT) demande à une ressource particulière à tout moment dans une application RESTful?

Cela semble être un scénario assez commun, mais je n'ai pas été en mesure de trouver une réponse définitive sur la meilleure façon de le gérer. D'autres idées que j'ai pris en compte et mis au rebut comprennent en quelque sorte sérialisation demandes du même client (peut-être basé sur la session HTTP) afin qu'ils soient traités dans l'ordre, la mise en œuvre d'une « file d'attente » des mises à jour pour un thread de travail JPA / Hibernate, et l'insertion d'une nouvelle versions » de la ressource tout en gardant une trace de la dernière mise à jour de l'un plutôt que de tout document unique.

Des pensées? Est-ce que la « une mise à jour exceptionnelle à la fois » limitation du client semble raisonnable, ou est-il une meilleure approche?

Créé 17/08/2010 à 17:05
source utilisateur
Dans d'autres langues...                            


2 réponses

voix
0

J'ai rencontré les mêmes problèmes de clients effectuant des opérations PUT simultanés vers le même URI en même temps. Il n'a pas de sens pour un client de le faire, mais je ne pense pas que vous trouverez toute la documentation difficile qui dit qu'il est interdit ou tout degré d'être RESTful. En effet, un serveur ne peut pas faire autre chose que les sérialiser et se plaignent de la concurrence optimiste quand il arrive. Un client bien comporté ferait sage d'éviter ces en synchronisant toutes les opérations sur chaque ressource, même la sécurité des opérations telles que GET ou HEAD, de sorte que vous ne pollue pas vos caches avec des données périmées.

Créé 17/08/2010 à 20:02
source utilisateur

voix
0

Mon premier problème était de savoir comment mettre à jour l'entité gérée à partir de la base de données avec l'objet non géré provenant du client. Étant donné que les données envoyées au client omet délibérément les clés de la base de données, c'était un peu pénible car il est descendu explicitement « la fusion » des éléments de l'objet non géré dans l'objet Mise en veille prolongée. Ce n'est pas ma question, mais si quelqu'un sait d'une façon élégante de le faire, je serais très intéressé d'entendre parler.

Soit vous devez inclure l'identifiant à la ressource que le client envoie ou utilisation PUT (par exemple PUT /object/{objectId}). Ensuite , vous n'avez pas besoin de fusionner mais juste « remplacer ». Je préfère toujours revenir et attendre des ressources complètes. Il éviter la fusion dégueu.

Mon second problème, et l'objet de ce post, se produit lorsque j'appuie sur le bouton « Enregistrer et fermer » dans le même temps que l'opération de sauvegarde automatique je l'ai mentionné plus tôt est en cours. Plus souvent qu'autrement, je reçois une exception de verrouillage optimiste. En effet, la seconde opération de mise à jour est en cours de traitement dans un thread séparé tandis que la première est encore en cours de traitement.

Comme vous l'avez mentionné, vous pouvez le faire sur côté client par JavaScript. Vous pouvez introduire un drapeau « sale » et à la fois l'auto-enregistrer ou le bouton d'enregistrement de près transmettre uniquement une demande au serveur lorsque le drapeau « sale » est réglé. Le drapeau « sale » est basculée, lorsque l'utilisateur a changé quelque chose. Je ne laisserais pas les demandes de sérialisation du serveur, cela complique les choses.

[...] Cependant, je crains que forcer cette limitation sur le client peut être écarter de l'esprit de repos. Est-il raisonnable d'attendre un client donné d'avoir plus d'une exceptionnelle « mise à jour » (PUT) demande à une ressource particulière à tout moment dans une application RESTful?

Une partie de l'esprit de repos est de découpler des choses et le client peut ainsi décider quand faire des opérations CRUD.

BTW: Il y a un cadre frontend java-script qui va très bien avec les APIs REST: ExtJS . Il a bien fonctionné pour nous pour des applications internes (je ne ferais pas un site Web public avec ExtJS en raison de l'apparence de style ExtJS & feel).

Créé 17/08/2010 à 19:04
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more