Faraday: Rety Middleware ne s'exécutera pas après l'analyseur

Créé le 23 avr. 2021  ·  4Commentaires  ·  Source: lostisland/faraday

Informations de base

  • Version Faraday : 1.4.1
  • Version Rubis : 2.7.2

Description du problème

_NB : Veuillez me faire savoir si cela appartient à faraday_middleware place. Comme il s'agit de deux middlewares, je ne savais pas où le mettre._

Lors de la création d'une connexion, je m'attends (comme cela est documenté) à ce que le middleware s'exécute dans l'ordre dans lequel il est déclaré. Cependant, lorsqu'une requête échoue et que je charge le :json middleware d'analyse suivi du :retry middleware, env.body n'est pas analysé dans le cadre du :retry middleware :retry_if bloc :

Je dois exécuter le bloc :retry_if sur le message décodé JSON car le document JSON peut être très volumineux si la demande aboutit, et l'alternative consiste à l'analyser une deuxième fois dans le retry_if , ce qui semble totalement inutile.

Étapes à reproduire

<strong i="23">@_client</strong> ||= Faraday.new(url: ROOT_URL) do |f|
      f.options[:timeout] = 10
      f.headers['Content-Type'] = 'application/json'
      f.use :instrumentation, name: INSTRUMENTATION_EVENT_NAME
      f.response :json, content_type: /\bjson$/
      f.request :retry, FARADAY_RETRY_OPTIONS
end

Remarque : si j'imprime f.instance_variable_get :@handlers , à l'intérieur du bloc, je vois le middleware dans l'ordre où je l'ai déclaré.

Lorsqu'une requête échoue et que j'évalue ces expressions dans le bloc :retry middleware :retry_if , j'obtiens le résultat suivant :

(byebug) environment.response.to_hash.without(:url)
{:status=>405, :body=>"{\"message\": \"The method is not allowed for the requested URL.\"}\n", :response_headers=>{"date"=>"Fri, 23 Apr 2021 18:17:16 GMT", "content-type"=>"application/json", "content-length"=>"64", "connection"=>"keep-alive", "server"=>"gunicorn", "allow"=>"HEAD, OPTIONS, GET"}}

(byebug) environment.response.body
"{\"message\": \"The method is not allowed for the requested URL.\"}\n"
(byebug) environment.response.body.class
String

Fondamentalement, le middleware d'analyse refuse simplement de s'exécuter en premier.

Le JSON est bien formé et l'en-tête Content-Type la réponse est correctement défini, donc je suis perplexe.

Ma seule supposition est que c'est quelque chose à voir avec #response middleware s'exécute toujours avant #request middleware, mais dans ce cas retry étant #request middleware est quelque chose d'un abus de langage car il doit implicitement être évalué après le retour de la réponse.

Commentaire le plus utile

Salut @mvastola , ce que vous rencontrez est le comportement attendu !
Je sais qu'il est difficile de comprendre au début, mais étant donné que la nature de la pile middleware est similaire à celle d'une pile de rack, les middleware sont parcourus dans l'ordre inverse des réponses.
Dans notre site Web, nous avons une image qui illustre cela pour le rendre plus facile à comprendre.

Donc tu as déjà fait ce qu'il fallait ! En déplaçant le :json middleware après le :retry , vous autorisez le traitement de la réponse par ce premier, et le :retry middleware trouvera le corps de la réponse analysé.

Je ferme ceci maintenant, mais n'hésitez pas à faire un suivi si vous avez d'autres questions

Tous les 4 commentaires

Mise à jour : j'ai littéralement inversé l'ordre des deux middlewares dans le bloc de configuration de connexion (en pensant "cela ne peut pas fonctionner") et maintenant cela fonctionne parfaitement. Laissant ceci cependant parce que je n'ai aucune idée de ce qui se passe et cela semble toujours être un bogue (ou du moins devrait être mieux documenté).

Salut @mvastola , ce que vous rencontrez est le comportement attendu !
Je sais qu'il est difficile de comprendre au début, mais étant donné que la nature de la pile middleware est similaire à celle d'une pile de rack, les middleware sont parcourus dans l'ordre inverse des réponses.
Dans notre site Web, nous avons une image qui illustre cela pour le rendre plus facile à comprendre.

Donc tu as déjà fait ce qu'il fallait ! En déplaçant le :json middleware après le :retry , vous autorisez le traitement de la réponse par ce premier, et le :retry middleware trouvera le corps de la réponse analysé.

Je ferme ceci maintenant, mais n'hésitez pas à faire un suivi si vous avez d'autres questions

Merci pour l'explication rapide, gentille et complète. Ce n'est pas si difficile à comprendre, mais c'est un peu peu intuitif ici. Je me demande s'il existe un moyen efficace de le faire moins.

Documents

J'avais en fait vu la documentation que vous avez liée, et cela m'a fait penser que je savais ce que je devais faire. (J'ai vu la photo et les trucs sur le middleware "le plus interne", mais je n'ai pas vraiment compris que cela signifiait inverser l'ordre.)

L'image affichée est informative en ce qui concerne les composants internes du middleware, mais il peut être utile de la compléter avec une indication visuelle de la façon dont l'ordre dans le bloc de configuration affecte l'ordre d'exécution.

Configuration

Au-delà de cela, il y a un tas de détails de cette implémentation qui rendent cela peu intuitif :

  • Il y a trois fonctions différentes dans faraday pour ajouter un middleware, et elles ne sont pas interchangeables : chaque middleware semble ne fonctionner qu'avec l'un d'entre eux. Cela donne l'impression qu'il existe trois piles (ou ordres) de middleware différentes, indépendantes les unes des autres.

  • Ce que font ces trois différents noms/groupes de middleware n'est pas clair, cependant, étant donné que la plupart des middleware ne _pas_ s'exécutent aux deux extrémités du chemin requête->réponse, un utilisateur serait susceptible de supposer que les tâches de « requête » se produisent toujours avant la « réponse » choses liées.

  • Le mot-clé rack pour ajouter un middleware, use , s'applique (pour autant que je sache) dans Faraday uniquement à ce type de middleware - un middleware qui enveloppe à la fois la demande et la réponse.

Quoi qu'il en soit, je suis heureux d'essayer de trouver des idées si vous êtes prêt à peaufiner l'API pour ce problème. Sinon au moins je comprends ça maintenant. Je dis seulement cela parce que je peux facilement voir d'autres utilisateurs souffrir de la même confusion ici.

Merci @mvastola , c'est un retour inestimable !
Et pour être honnête, ce n'est pas la première fois que j'entends parler de ces choses.

En ce qui concerne la documentation, je suis d'accord que nous sommes loin, donc toute contribution à l'amélioration est la bienvenue (il y a en fait un fil de discussion très récent à ce sujet !).

Les points sur la configuration sont également très valables, permettez-moi simplement de dire que la confusion des méthodes request , response et use a été soulevée plusieurs fois, au point que je suis en fait, envisagez simplement de les supprimer au profit de use , laissant ensuite au middleware le soin de documenter quoi/quand ils manipuleront la demande/réponse.
Je suggérerais donc de ne pousser aucun PR à changer cette API pour l'instant, mais nous sommes très ouverts à entendre la communauté sur ce sujet via des discussions

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

mattmill30 picture mattmill30  ·  4Commentaires

QuinnWilton picture QuinnWilton  ·  4Commentaires

jordansissel picture jordansissel  ·  5Commentaires

jeffb-stell picture jeffb-stell  ·  5Commentaires

ryanbyon picture ryanbyon  ·  3Commentaires