2008-12-30 7 views
9

Sto lavorando su una libreria Python che si interfaccia con un'API del servizio web. Come molti servizi web che ho incontrato, questo richiede di limitare la frequenza delle richieste. Vorrei fornire un parametro facoltativo, limit, all'istanza di classe che, se fornita, manterrà richieste in uscita fino a quando non passerà il numero di secondi specificato.Come limitare la velocità delle richieste ai servizi Web in Python?

Comprendo che lo scenario generale è il seguente: un'istanza della classe effettua una richiesta tramite un metodo. Quando lo fa, il metodo emette un segnale che imposta una variabile di blocco da qualche parte, e inizia un conto alla rovescia per il numero di secondi in limit. (Con ogni probabilità, il blocco è il conto alla rovescia stesso.) Se viene fatta un'altra richiesta entro questo intervallo di tempo, deve essere accodata fino a quando il timer per il conto alla rovescia raggiunge lo zero e il blocco è disattivato; a questo punto, viene inviata la richiesta più vecchia in coda e il timer per il conto alla rovescia viene ripristinato e il blocco viene reimpostato.

Si tratta di un caso per la filettatura? C'è un altro approccio che non vedo?

Se il conto alla rovescia e il blocco devono essere variabili di istanza o devono appartenere alla classe, in modo tale che tutte le istanze della classe tengano richieste?

Inoltre, è generalmente una cattiva idea fornire funzionalità di limitazione della velocità all'interno di una libreria? Ho ragione dal momento che, per impostazione predefinita, il conto alla rovescia è zero secondi, la libreria consente comunque agli sviluppatori di utilizzare la libreria e fornire i propri schemi di limitazione della velocità. Dato che tutti gli sviluppatori che utilizzano il servizio dovranno comunque richiedere un limite di velocità, tuttavia, immagino che sarebbe una comodità per la libreria fornire un mezzo di limitazione della velocità.

Indipendentemente dal posizionamento di uno schema di limitazione della velocità nella libreria o meno, voglio scrivere un'applicazione utilizzando la libreria, quindi le tecniche suggerite saranno utili.

Mille grazie per i vostri suggerimenti!

Chris

risposta

6

Questo funziona meglio con una coda e un dispatcher.

di dividere il processo in due parti: sorgente e spedizione. Questi possono essere thread separati (o processi separati se è più semplice).

Il lato Source crea e accoda le richieste a qualunque velocità li renda felici.

Il numero Dispatch fa questo.

  1. Ottenere la richiesta ora di inizio, s.

  2. Elimina una richiesta, elabora la richiesta tramite il servizio remoto.

  3. Ottenere l'ora corrente, t. Sleep per la tariffa - (t - s) secondi.

Se si desidera eseguire il lato sorgente collegata direttamente al servizio remoto, è possibile farlo, e il tasso di bypass limitante. Questo è utile per i test interni con una versione fittizia del servizio remoto.

La parte difficile di questo è creare una rappresentazione per ogni richiesta che è possibile accodare. Dal momento che Python Queue gestirà quasi tutto, non devi fare molto.

Se si utilizza la multielaborazione, è necessario disporre degli oggetti pickle per inserirli in una pipe.

1

Il tuo schema di limitazione della velocità dovrebbe essere fortemente influenzato dalle convenzioni di chiamata del codice sottostante (sincrono o asincrono), nonché da quale ambito (thread, processo, macchina, cluster?) Funzionerà a velocità limite.

Suggerirei di mantenere tutte le variabili all'interno dell'istanza, in modo da poter facilmente implementare più periodi/tassi di controllo.

Infine, sembra che tu voglia essere un componente middleware. Non cercare di essere un'applicazione e introdurre discussioni da solo. Basta bloccare/dormire se sei sincrono e usa il framework di dispacciamento asincrono se sei chiamato da uno di loro.

2

L'accodamento potrebbe essere eccessivamente complicato. Una soluzione più semplice consiste nel fornire alla classe una variabile per il momento in cui è stato chiamato l'ultimo servizio. Ogni volta che viene chiamato il servizio (! 1), impostare waitTime su delay - Now + lastcalltime. delay dovrebbe essere uguale al tempo minimo consentito tra le richieste. Se questo numero è positivo, attendere fino a quel punto prima di effettuare la chiamata (! 2). Lo svantaggio/vantaggio di questo approccio è che tratta le richieste di servizi Web come sincrone. Il vantaggio è che è assurdamente semplice e facile da implementare.

  • (! 1): dovrebbe accadere subito dopo aver ricevuto una risposta dal servizio, all'interno del wrapper (probabilmente nella parte inferiore del wrapper).
  • (! 2): deve verificarsi quando viene chiamato il wrapper python attorno al servizio Web, nella parte superiore del wrapper.

La soluzione di S.Lott è più elegante, ovviamente.

1

Se la tua libreria è progettata per essere sincrona, allora ti consiglio di escludere l'applicazione dei limiti (sebbene tu possa tenere traccia delle tariffe e almeno aiutare il chiamante a decidere come rispettare i limiti).

Io uso twisted per interfacciarlo con praticamente tutto oggigiorno. Rende facile fare quel tipo di cose avendo un modello che separa l'invio della richiesta dalla gestione della risposta. Se non vuoi che i tuoi utenti API debbano usare twisted, almeno staresti meglio a capire la loro API per l'esecuzione posticipata.

Ad esempio, ho un'interfaccia di twitter che spinge un numero piuttosto assurdo di richieste attraverso per conto di xmpp users. Non valuto il limite, ma ho dovuto fare un po 'di lavoro per evitare che tutte le richieste accadessero nello stesso momento.

0

quindi presumo qualcosa di semplice come tempo di importazione time.sleep (2) non funzionerà per attendere 2 secondi tra le richieste

+0

Bad ipotesi. Aspetta 2 secondi.Quello sarà 2 secondi. tra la fine di uno e l'inizio di un altro. Di solito vuoi 2 sec. tra l'inizio di uno e l'inizio di un altro. –

+0

Bene, attendere 2 secondi tra la fine di uno e l'inizio di un altro può essere più sicuro se i limiti vengono eseguiti in base all'ora effettiva tra le chiamate. Il vero problema è che la soluzione attende più di 2 secondi tra le richieste, poiché il calcolo tra le richieste potrebbe richiedere del tempo. – Brian