2010-09-03 4 views
11

Czytając Google App Engine documentation na asynchronicznym URL Fetch:Co się stanie, jeśli aplikacja wywoła więcej niż 10 asynchronicznych pobrań adresu URL w Google App Engine?

Aplikacja może mieć maksymalnie 10 jednoczesnych asynchroniczny URL Fetch połączeń

Co się stanie, jeśli aplikacja wymaga więcej niż 10 asynchroniczny sprowadzić na czas?
Czy Google App Engine zgłasza wyjątek lub po prostu umieszcza w kolejce pozostałe połączenia oczekujące na ich wyświetlanie?

Odpowiedz

9

Umm, Swizzec jest niepoprawny. Łatwo przetestować:

rpc = [] 
for i in range(1,20): 
    rpc.append(urlfetch.createrpc()) 
    urlfetch.make_fetch_call(rpc[-1],"http://stackoverflow.com/questions/3639855/what-happens-if-i-call-more-than-10-asynchronous-url-fetch") 

for r in rpc: 
    response = r.get_result().status_code 

Nie zwróci żadnych wyjątków. W rzeczywistości działa to dobrze! Pamiętaj, że Twoje wyniki mogą się różnić w przypadku aplikacji, które nie są płatne.

To, co raportuje Swizec, to inny problem, związany z maksymalnymi jednoczesnymi połączeniami do twojej aplikacji. W przypadku aplikacji rozliczanych nie ma tu praktycznego ograniczenia, po prostu się skaluje (zgodnie z zasadą 1000ms).

GAE nie może wiedzieć, że Twój moduł obsługi zgłoszeń wyda blokujący adres URL, więc połączenie 500, które widzi, nie jest związane z jego aplikacją (to nadmierne uproszczenie, jeśli twój średni czas odpowiedzi na żądanie jest> 1000 ms, co do prawdopodobieństwa wzrostu o 500).

+1

Z mojego doświadczenia wynika, że ​​Swizec nie jest w błędzie. Zobacz moją odpowiedź poniżej. –

5

500 błędów zaczyna się dziać. Bezgłośnie.

Dowiesz się o nich tylko, gdy spojrzysz na swój dziennik pod wszystkimi żądaniami (nie zostaną wyświetlone jako błędy). Mówi po prostu: "Żądanie zostało przerwane, ponieważ osiągnąłeś limit jednoczesnych żądań".

Tak więc, gdy wykonujesz wiele asynchronicznych wywołań, upewnij się, że możesz obsłużyć niektóre z nich spazzing out.

+0

pamiętajcie to samo dzieje się w przypadku wszelkich żądań. Jak jedzenie przez kolejkę zadań lub takie. Wygląda na to, że jeśli twoje odpowiedzi są bardzo szybkie (poniżej 100ms), Google jest skłonny znieść dużo i nie rzuci tego błędu. –

+0

uhm .. to nie dzieje się z moją aplikacją (nie widzę 500 błędów).Jestem na skrzydle z 11-13 połączeniami. – systempuntoout

6

To stara sprawa, ale uważam, że przyjęte rozwiązanie jest błędne lub nieaktualne i może zmylić ludzi. Minęło kilka miesięcy, zanim faktycznie to przetestowałem, ale z mojego doświadczenia wynika, że ​​Swizec ma rację, że GAE nie będzie w kolejce, ale raczej zawiedzie większość asynchronicznych pobrań adresów URL przekraczających limit równy około 10 jednoczesnych na żądanie.

Aby uzyskać opis limitu, zobacz https://developers.google.com/appengine/docs/python/urlfetch/#Python_Making_requests i https://groups.google.com/forum/#!topic/google-appengine/EoYTmnDvg8U.

David Underhill wymyślił URL Fetch Manager for Python, który umieszcza w kolejce asynchroniczne pobrane adresy URL, które przekraczają limit kodu aplikacji.

I wprowadziły coś podobnego dla Java, który synchronicznie bloki (z powodu braku funkcji zwrotnej lub ListenableFutures) dodatkowe życzenia:

/** 
* A URLFetchService wrapper that ensures that only 10 simultaneous asynchronous fetch requests are scheduled. If the 
* limit is reached, the fetchAsync operations will block until another request completes. 
*/ 
public class BlockingURLFetchService implements URLFetchService { 
    private final static int MAX_SIMULTANEOUS_ASYNC_REQUESTS = 10; 

    private final URLFetchService urlFetchService = URLFetchServiceFactory.getURLFetchService(); 
    private final Queue<Future<HTTPResponse>> activeFetches = new LinkedList<>(); 

    @Override 
    public HTTPResponse fetch(URL url) throws IOException { 
     return urlFetchService.fetch(url); 
    } 

    @Override 
    public HTTPResponse fetch(HTTPRequest request) throws IOException { 
     return urlFetchService.fetch(request); 
    } 

    @Override 
    public Future<HTTPResponse> fetchAsync(URL url) { 
     block(); 

     Future<HTTPResponse> future = urlFetchService.fetchAsync(url); 
     activeFetches.add(future); 
     return future; 
    } 

    @Override 
    public Future<HTTPResponse> fetchAsync(HTTPRequest request) { 
     block(); 

     Future<HTTPResponse> future = urlFetchService.fetchAsync(request); 
     activeFetches.add(future); 
     return future; 
    } 

    private void block() { 
     while (activeFetches.size() >= MAX_SIMULTANEOUS_ASYNC_REQUESTS) { 
      // Max. simultaneous async requests reached; wait for one to complete 
      Iterator<Future<HTTPResponse>> it = activeFetches.iterator(); 
      while (it.hasNext()) { 
       if (it.next().isDone()) { 
        it.remove(); 
        break; 
       } 
      } 
     } 
    } 
}