Faraday: Rety Middleware não funciona após o analisador

Criado em 23 abr. 2021  ·  4Comentários  ·  Fonte: lostisland/faraday

Informação básica

  • Versão Faraday: 1.4.1
  • Versão Ruby: 2.7.2

Descrição do problema

_NB: Por favor, deixe-me saber se isso pertence a faraday_middleware . Como se trata de dois middlewares, não sabia onde colocá-lo._

Ao criar uma conexão, espero (conforme documentado) que o middleware será executado na ordem em que foi declarado. No entanto, quando uma solicitação falha e eu carrego o middleware de análise :json seguido pelo middleware :retry , env.body não é analisado no escopo do :retry middleware :retry_if Bloco de

Eu preciso para executar o :retry_if bloco no JSON mensagem -decoded porque o documento JSON pode ser muito grande se o pedido for bem sucedida, e a alternativa é analisá-lo uma segunda vez no retry_if , o que parece totalmente desnecessário.

Passos para reproduzir

<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

Nota: Se eu imprimir f.instance_variable_get :@handlers , dentro do bloco, vejo o middleware na ordem em que o declarei.

Quando uma solicitação falha e eu avalio essas expressões no bloco :retry middleware :retry_if , obtenho a seguinte saída:

(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

Basicamente, o middleware de análise simplesmente se recusa a ser executado primeiro.

O JSON está bem formado e o cabeçalho Content-Type da resposta está definido corretamente, por isso estou perplexo.

Meu único palpite é que tem algo a ver com #response middleware sempre executado antes de #request middleware, mas neste caso retry sendo #request middleware é um nome impróprio porque ele precisa ser avaliado implicitamente após o retorno da resposta.

Comentários muito úteis

Olá @mvastola , o que você está experimentando é o comportamento esperado!
Eu sei que é difícil entender isso no início, mas dada a natureza da pilha de middleware ser semelhante à de uma pilha de rack, o middleware é percorrido em ordem reversa para as respostas.
Em nosso site temos uma imagem que ilustra isso para tornar mais fácil de entender.

Portanto, você já fez a coisa certa 🙌! Movendo o middleware :json após o :retry one, você permite que a resposta seja processada por aquele primeiro, e o middleware :retry encontrará o corpo da resposta analisado.

Estou encerrando isso agora, mas fique à vontade para fazer o acompanhamento se tiver mais perguntas

Todos 4 comentários

Atualização: Eu literalmente inverti a ordem dos dois middlewares no bloco de configuração de conexão (pensando "isso não pode funcionar") e agora funciona perfeitamente. Saindo disso porque não tenho ideia do que está acontecendo e ainda parece um bug (ou pelo menos deveria ser melhor documentado).

Olá @mvastola , o que você está experimentando é o comportamento esperado!
Eu sei que é difícil entender isso no início, mas dada a natureza da pilha de middleware ser semelhante à de uma pilha de rack, o middleware é percorrido em ordem reversa para as respostas.
Em nosso site temos uma imagem que ilustra isso para tornar mais fácil de entender.

Portanto, você já fez a coisa certa 🙌! Movendo o middleware :json após o :retry one, você permite que a resposta seja processada por aquele primeiro, e o middleware :retry encontrará o corpo da resposta analisado.

Estou encerrando isso agora, mas fique à vontade para fazer o acompanhamento se tiver mais perguntas

Obrigado pela explicação rápida, gentil e completa. Não é tão difícil de entender, mas é um pouco pouco intuitivo aqui. Eu me pergunto se há uma maneira eficaz de diminuir isso.

Docs

Na verdade, eu tinha visto a documentação que você vinculou e isso me fez pensar que sabia o que precisava fazer. (Eu vi a imagem e o material sobre o middleware "mais interno", mas não processei realmente que significava inverter a ordem.)

A imagem mostrada é informativa em relação à parte interna do middleware, mas pode ser útil complementá-la com uma indicação visual de como a ordem no bloco de configuração afeta a ordem de execução.

Configuração

Além disso, há vários detalhes dessa implementação que a tornam pouco intuitiva:

  • Existem três funções diferentes em faraday para adicionar middleware, e elas não são intercambiáveis: cada peça de middleware parece funcionar apenas com uma delas. Isso faz parecer que existem três pilhas (ou ordens) diferentes de Middleware, independentes umas das outras.

  • O que esses três nomes / grupos diferentes de Middleware fazem é muito obscuro, no entanto, uma vez que a maioria dos Middleware _não_ é executado em ambas as extremidades do caminho de solicitação-> resposta, um usuário estaria apto a assumir que tarefas de "solicitação" sempre acontecem antes da "resposta" coisas relacionadas.

  • A palavra-chave rack para adicionar middleware, use , se aplica (o melhor que posso dizer) em Faraday apenas para esse tipo de middleware - middleware que envolve tanto a solicitação quanto a resposta.

De qualquer forma, estou feliz em tentar pensar em algumas idéias se você estiver aberto para ajustar a API para este problema. Caso contrário, pelo menos eu entendo isso agora. Só estou dizendo isso porque posso ver facilmente outros usuários sofrendo da mesma confusão aqui.

Obrigado @mvastola , este é um feedback inestimável 🙏!
E para ser justo, não é a primeira vez que ouço falar dessas coisas.

Quando se trata de documentação, concordo que estamos muito distantes, então qualquer contribuição para melhorar isso é muito bem-vinda (na verdade, há um tópico de discussão muito recente sobre isso!).

Os pontos sobre configuração também são muito válidos, deixe-me apenas dizer que a confusão dos métodos request , response e use foi levantada várias vezes, a ponto de eu estar na verdade, considerando simplesmente descartá-los em favor de apenas ter use , deixando então para o middleware documentar o que / quando eles estarão manipulando a solicitação / resposta.
Então, eu sugiro não forçar nenhum PR para mudar essa API ainda, mas estamos muito abertos para ouvir a comunidade sobre este tópico por meio de discussões

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

aleksb86 picture aleksb86  ·  3Comentários

yykamei picture yykamei  ·  4Comentários

mattmill30 picture mattmill30  ·  4Comentários

QuinnWilton picture QuinnWilton  ·  4Comentários

Lewiscowles1986 picture Lewiscowles1986  ·  4Comentários