Faraday: Rety Middleware no se ejecutará después del analizador

Creado en 23 abr. 2021  ·  4Comentarios  ·  Fuente: lostisland/faraday

Información básica

  • Versión de Faraday: 1.4.1
  • Versión de Ruby: 2.7.2

Descripcion del problema

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

pasos para reproducir

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

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.

Todos 4 comentarios

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.

Docs

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.

Configuració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.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

olleolleolle picture olleolleolle  ·  5Comentarios

asf-stripe picture asf-stripe  ·  3Comentarios

luizkowalski picture luizkowalski  ·  3Comentarios

jordansissel picture jordansissel  ·  5Comentarios

ryanbyon picture ryanbyon  ·  3Comentarios