_NB: Por favor, avíseme si esto pertenece a faraday_middleware
lugar. Como se trata de dos middlewares, no sabía dónde ponerlo.
Al crear una conexión, espero (como está documentado) que el middleware se ejecutará en el orden en que se declaró. Sin embargo, cuando una solicitud falla y cargo el :json
middleware de análisis seguido del :retry
middleware, env.body
se analiza en el alcance del :retry
middleware :retry_if
bloque:
Necesito ejecutar el bloque :retry_if
en el mensaje JSON
codificado porque el documento JSON puede ser muy grande si la solicitud es exitosa, y la alternativa es analizarlo por segunda vez en el retry_if
, que parece totalmente innecesario.
<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: Si imprimo f.instance_variable_get :@handlers
, dentro del bloque, veo el middleware en el orden en que lo declaré.
Cuando una solicitud falla y evalúo estas expresiones en el bloque :retry_if
del :retry
middleware, obtengo el siguiente resultado:
(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
Básicamente, el middleware de análisis simplemente se niega a ejecutarse primero.
El JSON está bien formado y el encabezado Content-Type
la respuesta está configurado correctamente, así que estoy perplejo.
Mi única suposición es que tiene algo que ver con #response
middleware siempre se ejecuta antes que #request
middleware, pero en este caso retry
siendo #request
middleware es un nombre inapropiado porque implícitamente necesita ser evaluado después de que se devuelva la respuesta.
Actualización: literalmente cambié el orden de los dos middlewares en el bloque de configuración de conexión (mientras pensaba "esto no puede funcionar") y ahora funciona perfectamente. Sin embargo, dejo esto porque no tengo idea de lo que está sucediendo y todavía parece un error (o al menos debería estar mejor documentado).
Hola @mvastola , ¡lo que estás experimentando es el comportamiento esperado!
Sé que es difícil entenderlo al principio, pero dada la naturaleza de la pila de middleware que es similar a la de una pila de rack, el middleware se recorre en orden inverso para las respuestas.
En nuestro sitio web tenemos una imagen que ilustra esto para que sea más fácil de entender.
¡Por eso ya hiciste lo correcto 🙌! Al mover el middleware :json
después del :retry
uno, permite que la respuesta sea procesada por ese primero, y el middleware :retry
encontrará el cuerpo de la respuesta analizado.
Estoy cerrando esto ahora, pero no dudes en hacer un seguimiento si tienes más preguntas.
Gracias por la explicación rápida, amable y completa. No es tan difícil de entender, pero aquí es un poco poco intuitivo. Me pregunto si hay una forma eficaz de hacerlo menos.
De hecho, había visto la documentación que vinculó y me hizo pensar que sabía lo que tenía que hacer. (Vi la imagen y las cosas sobre el middleware "más interno", pero realmente no procesé que significara invertir el orden).
La imagen que se muestra es informativa con respecto a los componentes internos del middleware, pero podría ser útil complementarla con una indicación visual de cómo el orden en el bloque de configuración afecta el orden de ejecución.
Más allá de eso, hay un montón de detalles de esta implementación que hacen que esto no sea intuitivo:
Hay tres funciones diferentes en faraday
para agregar middleware, y no son intercambiables: cada pieza de middleware parece funcionar solo con una de ellas. Esto hace que parezca que hay tres pilas (u órdenes) diferentes de Middleware independientes entre sí.
Lo que hacen estos tres nombres / grupos diferentes de Middleware no está muy claro, sin embargo, dado que la mayoría de Middleware _no_ se ejecuta en ambos extremos de la ruta de solicitud-> respuesta, un usuario podría asumir que las tareas de "solicitud" siempre ocurren antes de la "respuesta" cosas relacionadas.
La palabra clave de rack para agregar middleware, use
, se aplica (lo mejor que puedo decir) en Faraday solo a ese tipo de middleware, middleware que envuelve tanto la solicitud como la respuesta.
De todos modos, estoy feliz de intentar pensar en algunas ideas si está dispuesto a modificar la API para este problema. De lo contrario, al menos entiendo esto ahora. Solo digo esto porque puedo ver fácilmente a otros usuarios que sufren la misma confusión aquí.
Gracias @mvastola , este es un comentario invaluable 🙏!
Y para ser justos, esta no es la primera vez que escucho sobre estas cosas.
En lo que respecta a la documentación, estoy de acuerdo en que estamos muy lejos, por lo que cualquier contribución para mejorar eso es muy bienvenida (¡de hecho, hay un hilo de discusión muy reciente sobre eso!).
Los puntos sobre la configuración también son muy válidos, permítanme decir que la confusión de los métodos request
, response
y use
se ha planteado varias veces, hasta el punto de que estoy en realidad, considerando simplemente descartarlos a favor de solo tener use
, dejando que el middleware documente qué / cuándo manipularán la solicitud / respuesta.
Por lo tanto, sugeriría no presionar a ningún PR para que cambie esa API todavía, pero estamos muy abiertos a escuchar a la comunidad sobre este tema a través de discusiones.
Comentario más útil
Hola @mvastola , ¡lo que estás experimentando es el comportamiento esperado!
Sé que es difícil entenderlo al principio, pero dada la naturaleza de la pila de middleware que es similar a la de una pila de rack, el middleware se recorre en orden inverso para las respuestas.
En nuestro sitio web tenemos una imagen que ilustra esto para que sea más fácil de entender.
¡Por eso ya hiciste lo correcto 🙌! Al mover el middleware
:json
después del:retry
uno, permite que la respuesta sea procesada por ese primero, y el middleware:retry
encontrará el cuerpo de la respuesta analizado.Estoy cerrando esto ahora, pero no dudes en hacer un seguimiento si tienes más preguntas.