2008-12-30 14 views
9

Estoy trabajando en una biblioteca de Python que interactúa con una API de servicio web. Al igual que muchos servicios web que he encontrado, este solicita limitar la tasa de solicitudes. Me gustaría proporcionar un parámetro opcional, limit, a la creación de instancias de clase que, si se proporciona, contendrá las solicitudes salientes hasta que pase el número de segundos especificado.¿Cómo limitar la tasa de solicitudes a servicios web en Python?

Entiendo que el escenario general es el siguiente: una instancia de la clase realiza una solicitud a través de un método. Cuando lo hace, el método emite una señal que establece una variable de bloqueo en algún lugar, y comienza un temporizador de cuenta atrás para el número de segundos en limit. (Con toda probabilidad, el bloqueo es el propio temporizador de cuenta regresiva). Si se hace otra solicitud dentro de este marco de tiempo, debe ponerse en cola hasta que el temporizador de cuenta regresiva llegue a cero y el bloqueo se desactive; en este punto, se envía la solicitud más antigua en la cola, y se reinicia el temporizador de cuenta atrás y se vuelve a activar el bloqueo.

¿Es esto un caso para enhebrar? ¿Hay otro enfoque que no estoy viendo?

¿El temporizador de cuenta regresiva y el bloqueo deben ser variables de instancia, o deberían pertenecer a la clase, de modo que todas las instancias de la clase tengan solicitudes?

Además, ¿es generalmente una mala idea proporcionar funcionalidad de limitación de velocidad dentro de una biblioteca? Lo razono ya que, de forma predeterminada, la cuenta regresiva es de cero segundos, la biblioteca aún permite a los desarrolladores utilizar la biblioteca y proporcionar sus propios esquemas de limitación de velocidad. Dado que los desarrolladores que usen el servicio necesitarán limitar las solicitudes de todos modos, sin embargo, creo que sería una ventaja para la biblioteca proporcionar un medio para limitar las tasas.

Independientemente de colocar un esquema de limitación de velocidad en la biblioteca o no, querré escribir una aplicación usando la biblioteca, por lo que las técnicas sugeridas serán útiles.

Muchas gracias por sus sugerencias!

Chris

Respuesta

6

Esto funciona mejor con una cola y un despachador.

dividir su transformación en dos partes: fuente y envían. Estos pueden ser hilos separados (o procesos separados si es más fácil).

El lado Source crea y encola las solicitudes al ritmo que las hace felices.

El Despacho lado hace esto.

  1. obtener el tiempo de inicio para la solicitud, s.

  2. Dequeues a request, procesa la solicitud a través del servicio remoto.

  3. Obtener la hora actual, t. Suspensión para tasa - (t - s) segundos.

Si desea ejecutar el lado fuente conectada directamente al servicio remoto, se puede hacer eso, y la tasa de derivación limitante. Esto es bueno para las pruebas internas con una versión simulada del servicio remoto.

La parte difícil de esto es crear alguna representación para cada solicitud que puede enrutar. Dado que Python Queue se ocupará de casi cualquier cosa, no tiene que hacer mucho.

Si está utilizando procesamiento múltiple, tendrá que pickle sus objetos para ponerlos en una tubería.

1

Su esquema de limitación de velocidad debe estar fuertemente influenciado por las convenciones de llamada del código subyacente (syncronous o async), así como ¿en qué alcance (hilo, proceso, máquina, clúster) operará esta limitación de velocidad?

Sugeriría mantener todas las variables dentro de la instancia, para que pueda implementar fácilmente múltiples periodos/tasas de control.

Por último, parece que quiere ser un componente de middleware. No intente ser una aplicación e introduzca hilos por su cuenta. Simplemente bloquee/duerma si está sincronizado y use el marco de envío asincrónico si uno de ellos lo llama.

2

Hacer cola puede ser demasiado complicado. Una solución más simple es darle a su clase una variable para el momento en que se llamó por última vez al servicio. Siempre que se llame al servicio (! 1), establezca waitTime en delay - Now + lastcalltime. delay debe ser igual al tiempo mínimo permitido entre las solicitudes. Si este número es positivo, duerma por tanto tiempo antes de hacer la llamada (! 2). La desventaja/ventaja de este enfoque es que trata las solicitudes del servicio web como sincrónicas. La ventaja es que es absurdamente simple y fácil de implementar.

  • (! 1): Debería suceder inmediatamente después de recibir una respuesta del servicio, dentro del envoltorio (probablemente en la parte inferior del envoltorio).
  • (! 2): debería ocurrir cuando se llama al envoltorio de Python alrededor del servicio web, en la parte superior del contenedor.

La solución de S.Lott es más elegante, por supuesto.

1

Si su biblioteca está diseñada para ser sincrónica, entonces recomendaría dejar de lado la aplicación de límites (aunque puede rastrear las tasas y al menos ayudar a la persona que llama a decidir cómo respetar los límites).

Uso twisted para interactuar con prácticamente todo en la actualidad. Hace que sea fácil hacer ese tipo de cosas al tener un modelo que separa el envío de solicitudes del manejo de respuestas. Si no desea que los usuarios de la API tengan que utilizar twisted, al menos sería mejor que entendiera su API para la ejecución diferida.

Por ejemplo, tengo una interfaz de Twitter que envía un número bastante absurdo de solicitudes en nombre de xmpp users. No califico el límite, pero tuve que trabajar un poco para evitar que todas las solicitudes tuvieran lugar al mismo tiempo.

0

así que estoy asumiendo algo tan simple como tiempo de importación time.sleep (2) no funcionará para esperar 2 segundos entre las peticiones

+0

supuesto Bad. Espera 2 segundos.Eso será 2 seg. entre el final de uno y el comienzo de otro. Usualmente quieres 2 seg. entre el comienzo de uno y el comienzo de otro. –

+0

Bueno, esperar 2 segundos entre el final de uno y el inicio de otro puede ser más seguro si los límites se basan en el tiempo real entre llamadas. El problema real es que la solución espera más de 2 entre solicitudes, ya que el cálculo entre solicitudes puede llevar tiempo. – Brian

Cuestiones relacionadas