_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.
<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.
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.
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.
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
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