Pourquoi les programmeurs devraient-ils s'en préoccuper ?
L'idempotence est un concept qu'il est important de comprendre pour les programmeurs, en particulier ceux qui travaillent à la construction de systèmes distribués. En termes simples, l'idempotence signifie que si vous effectuez une opération plusieurs fois, le résultat final doit être le même que si vous ne l'aviez effectuée qu'une seule fois.
En d'autres termes, une opération idempotente est une opération qui peut être répétée plusieurs fois sans provoquer d'effets secondaires supplémentaires. Cette notion est importante dans les systèmes distribués, car les messages peuvent parfois être perdus ou dupliqués en raison de problèmes de réseau, et si une opération n'est pas idempotente, sa répétition peut avoir des conséquences inattendues.
Supposons que vous construisiez une API pour le traitement des paiements. Si vous concevez l'API en tenant compte de l'idempotence, vous pouvez vous assurer que même si la même demande de paiement est envoyée plusieurs fois en raison de problèmes de réseau, elle ne sera traitée qu'une seule fois. Cela permet d'éviter que les clients soient facturés deux fois, ce qui peut entraîner des problèmes de confiance et des pertes de revenus.
"La "même" requête qui frappe votre API ne doit pas modifier votre état pour la deuxième fois". (Milan Jovanović - Tweet)
Un peu plus sur les API idempotentes
Nous utilisons de nombreuses méthodes pour concevoir nos systèmes afin de tolérer et de réduire la probabilité de défaillance et d'éviter de transformer un petit pourcentage de défaillances en une panne complète. Certaines de ces méthodes sont particulièrement vitales dans les systèmes distribués.
Supposons que nous ayons une application de commande de produits alimentaires et, pour que notre application reste simple, que nous ayons deux services de base, l'expédition et la commande. Lorsque l'un de nos clients passe une commande, celle-ci est d'abord créée, puis les instructions d'expédition sont créées. Si toutes les transactions sont réussies, une notification est envoyée au client. Même dans ce scénario simple, de nombreuses défaillances peuvent se produire. Ces défaillances peuvent provenir de différents facteurs. Il peut s'agir de serveurs, de réseaux, d'équilibreurs de charge, de logiciels, de systèmes d'exploitation ou même d'erreurs commises par les opérateurs du système. Par exemple, même si le service de commande et d'expédition fait correctement son travail, que se passe-t-il si le client ne peut pas recevoir de réponse en raison de la latence du réseau lors du retour de la réponse ? Bien sûr, la première chose qui vient à l'esprit dans de tels cas est d'utiliser des modèles tels que le timeout, le retry et le backoff. Mais que se passe-t-il si nous réessayons l'appel de service dans ce scénario ? S'agit-il d'une situation que nous voulons réorganiser ? Réessayer la requête peut entraîner des commandes multiples avec des conséquences très graves. C'est pourquoi il est important de concevoir des API idempotentes.
L'idempotence avec les méthodes HTTP
HTTP (Hypertext Transfer Protocol) est un protocole largement utilisé pour la communication entre les serveurs web et les clients. L'idempotence joue un rôle important dans la conception des méthodes HTTP, qui sont utilisées pour définir le type d'action qu'un client souhaite effectuer sur une ressource. Dans cette section, nous verrons comment l'idempotence s'applique à certaines méthodes HTTP.
- Méthode GET : La méthode GET est utilisée pour récupérer une ressource sur le serveur. Il s'agit d'une méthode idempotente car la récupération de la même ressource plusieurs fois ne modifiera pas la ressource elle-même et ne provoquera pas d'effets secondaires sur le serveur.
- Méthode PUT : La méthode PUT est utilisée pour mettre à jour une ressource sur le serveur. Elle est idempotente, car le fait d'envoyer plusieurs fois la même requête aboutira au même état de la ressource que si la requête n'avait été envoyée qu'une seule fois. Par exemple, si vous envoyez plusieurs fois une requête PUT pour mettre à jour l'adresse électronique d'un utilisateur avec la même nouvelle adresse électronique, l'adresse électronique de l'utilisateur ne sera mise à jour qu'une seule fois.
- Méthode DELETE : La méthode DELETE est utilisée pour supprimer une ressource du serveur. Elle est idempotente, car la suppression d'une ressource plusieurs fois aura le même résultat que sa suppression une seule fois. Si la ressource a déjà été supprimée, l'envoi d'une demande DELETE pour la même ressource n'entraînera aucune modification.
- Méthode POST : La méthode POST est utilisée pour créer une nouvelle ressource sur le serveur ou pour soumettre des données à traiter. Elle n'est pas idempotente, car le fait d'envoyer la même requête plusieurs fois créera plusieurs ressources ou soumettra les mêmes données plusieurs fois, ce qui entraînera des résultats différents.
Comment réaliser l'idempotence dans la méthode POST ?
Dans un système distribué où de nombreux clients effectuent de nombreux appels et où de nombreuses requêtes sont en cours, le défi consiste à savoir comment identifier qu'une requête est une répétition d'une requête précédente.
Il est possible de rendre une requête POST idempotente en incluant un identifiant unique dans le corps de la requête ou dans l'en-tête, qui peut être utilisé pour identifier et empêcher les requêtes en double.
De nombreuses approches peuvent être utilisées pour déterminer si une demande est une copie d'une demande antérieure. Par exemple, il est possible de dériver un jeton synthétique sur la base des paramètres de la demande. Vous pouvez dériver un hachage des paramètres existants et supposer que toute demande avec les mêmes paramètres provenant du même appelant est un doublon. À première vue, cela semble simplifier à la fois l'expérience du client et la mise en œuvre du service. Toute demande qui ressemble exactement à une demande précédente est considérée comme une demande dupliquée. Cependant, il est peu probable que cette approche fonctionne dans toutes les situations. Par exemple, si vous commandez un repas et que votre voisin commande le même repas, ces demandes sont-elles répétées ou s'agit-il de deux demandes différentes ? Ou encore, après avoir passé une commande, votre ami vous appelle pour vous dire qu'il a faim, et lorsque vous recréez la même commande peu de temps après, allons-nous considérer qu'il s'agit de deux demandes renouvelées ? Ce scénario est-il très similaire à celui du client qui réessaie le service en raison de la latence du réseau que nous venons de mentionner ? Il est possible que l'appelant souhaite en fait deux repas identiques.
L'approche généralement privilégiée consiste à inclure dans le contrat d'API un identifiant de demande client unique fourni par l'appelant. Les demandes provenant du même appelant avec le même identifiant de demande client peuvent être considérées comme des demandes en double et traitées en conséquence. Un identifiant de demande client unique fourni par l'appelant pour les opérations idempotentes répond à ce besoin.
Le diagramme suivant montre un exemple de flux de demande/réponse qui utilise un identifiant de demande client unique dans un scénario de répétition idempotente :
Dans cet exemple, un client demande la création d'une ressource qui présente un identifiant de demande client unique. À la réception de la demande, le service vérifie d'abord s'il a déjà vu cet identifiant. Si ce n'est pas le cas, il commence à traiter la demande. Il crée et stocke une "session" idempotente pour cette demande, dont la clé est l'identifiant du client et son identifiant unique de demande de client. Si une demande ultérieure est reçue du même client avec le même identifiant unique de demande du client, le service sait qu'il a déjà vu cette demande et peut prendre les mesures qui s'imposent.
Deux points sont importants à cet égard. Le premier est la durée de stockage de l'identifiant unique de la demande du client et le second est l'échec de la transaction. Si la transaction n'aboutit pas, l'identifiant unique de la demande du client ne doit pas être créé, c'est-à-dire qu'il doit s'agir d'une transaction ACID.
Conclusion
Dans cet article, nous avons étudié comment l'idempotence s'applique aux méthodes HTTP, qui constituent un élément fondamental du développement web. Nous avons vu que certaines méthodes HTTP, telles que GET, PUT et DELETE, sont idempotentes, alors que d'autres, telles que POST, ne le sont pas. Il est essentiel de savoir quelles méthodes sont idempotentes pour construire des systèmes efficaces et fiables.
Globalement, la compréhension et l'implémentation de l'idempotence peuvent vous aider à construire des systèmes plus robustes et plus fiables, ce qui est crucial dans le monde actuel des systèmes distribués. Que vous soyez un développeur débutant ou expérimenté, la compréhension de l'idempotence est une compétence essentielle qui vous aidera à construire de meilleurs logiciels.
Source : Berkan Sasmaz, ingénieur logiciel
Et vous ?
Qu'en pensez-vous ?
Selon vous, le concept d'idempotence est-il un élément crucial pour garantir la prévisibilité et la fiabilité des opérations ?
Voir aussi
Quels sont les langages de programmation à conseiller à un débutant ? La panoplie des choix est déroutante dans un panier qui en compte des milliers dont on fait usage de par le monde
JetBrains lance un nouveau cours gratuit de programmation avec Rust, qui couvre une grande partie des besoins des apprenants