2014-09-30 9 views
9

Mam skrypt PHP, który wysyła żądanie do zdalnego interfejsu API. Jeśli odpowiedź zajmie więcej niż około 200 sekund, otrzymam w odpowiedzi długość treści równą zero. Próbuję zrozumieć, dlaczego tak się dzieje.Dlaczego Apache zwraca zerową długość treści po 200 sekundach na żądanie PHP POST?

Próbując rozwiązać ten problem, ustawiłem każdą możliwą zmienną w plikach konfiguracyjnych Apache i PHP na ponad 300 sekund, aby to zwalczyć, zgodnie z pierwszą odpowiedzą poniżej. Rzeczy, które mi zostały ustawione na 300 sekund:

  • Apache limitu czasu
  • czas Apache keep_alive
  • PHP max_reponse_time
  • czas PHP session.cache_expire
  • PHP max_execution_time

Mimo że wciąż konsekwentnie uzyskują odpowiedzi o zerowej długości treści w okolicach 200-sekundowego znaku. Jednak jeśli zajmie to mniej niż 200 sekund, problem nie występuje.

Poniżej opisuję, w jaki sposób konfigurowany jest nasz kod.

Co się dzieje, że crontab uruchamia skrypt powłoki na naszym serwerze, który wywołuje identyfikator URI hosta lokalnego za pomocą/usr/bin/curl. Lokalny identyfikator URI jest obsługiwany przez Apache i jest plikiem PHP, który sam zawiera poniższy kod, który z kolei używa cURL do wywoływania zdalnego interfejsu API. POSTUJEMY około 10 KB XML i oczekujemy, że otrzymamy około 135 KB z powrotem w porcjach.

Oto kod prośba:

 $ch = curl_init(); 
     curl_setopt($ch, CURLOPT_URL, $this->_xml_url); 
     curl_setopt($ch, CURLOPT_POST, true); 
     curl_setopt($ch, CURLOPT_VERBOSE, true); 
     curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml')); 
     curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_str); 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
     $output = curl_exec($ch);   
     curl_close($ch); 

włączyłem debugowanie w naszej logowania Apache i poniżej jest to, co mamy. W tym przykładzie prośba została wysłana o 19:48:00, a odpowiedź wróciła o 19:51:23, nieco ponad 200 sekund później.

* About to connect() to api.asdf.com port 443 (#0) 
* Trying 555.555.555.555... * connected 
* successfully set certificate verify locations: 
* CAfile: none 
    CApath: /etc/ssl/certs 
* SSL connection using RC4-SHA 
* Server certificate: 
* subject: snip 
* start date: 2014-03-12 10:22:02 GMT 
* expire date: 2015-04-16 12:32:58 GMT 
* subjectAltName: api.asdf.com matched 
* issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign Organization Validation CA - G2 
* SSL certificate verify ok. 
> POST /xmlservlet HTTP/1.1 

Host: api.asdf.com 
Accept: */* 
Content-Type: text/xml 
Content-Length: 10773 
Expect: 100-continue 

< HTTP/1.1 100 Continue 
< HTTP/1.1 200 OK 
< Cache-Control: private 
< Content-Type: text/xml 
< Server: Microsoft-IIS/7.5 
< X-AspNet-Version: 4.0.30319 
< X-Powered-By: ASP.NET 
< Date: Thu, 06 Nov 2014 19:51:23 GMT 
< Content-Length: 0 
< 

* Connection #0 to host api.asdf.com left intact 
* Closing connection #0 

Chciałbym wiedzieć, czy coś jest nie tak z tym kodem lub coś mogło mi brakowało w ustawieniach serwera, które mogłyby spowodować długość zawartość wrócić zera po 200 sekund.

+0

może to być związane ze statusem '100 Kontynuuj'. Spróbuj wyłączyć to w żądaniu CURL - 'curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ('Expect:', 'Content-Type: text/xml'));' – Cheery

+2

Myślę, że problem nie jest po twojej stronie .. do zdalnego hosta, do którego wysyłasz dane. Prawdopodobnie ustawienie limitu czasu serwera to 200s. –

+0

@SyedQarib Tak, jak zaznaczono we właściwej odpowiedzi, która wydaje się być bardzo prawdopodobna. – CommaToast

Odpowiedz

6

Brzmi bardzo podobnie do limitu czasu na zdalnym serwerze interfejsu API - spróbuj uzyskać do niego dostęp ręcznie, np. przez przeglądarkę lub wget.

+0

Myślę, że wygrasz. Próbowałem ręcznie uzyskać dostęp przez 'curl -m 1800 -v -S -H" Content-Type: application/xml "--data @ test.xml {MYURI}' i mam te same problemy, bez PHP ani Apache'a zaangażowany. Więc jeśli nie ma jakiejś opcji arcane curl, o której tutaj nie myślę, to myślę, że masz rację - zwłaszcza, że ​​podczas szukania w Google-IIS/7.5 uważam, że 200 sekund to wartość, którą zalecają do przekroczenia limitu czasu ... I nie mówię, że to Microsoft, ale to była Microsoft. Twoja sugestia, by spróbować wejść do niego ręcznie, doprowadziła mnie do wyeliminowania wystarczającej liczby innych możliwości, aby być na 99% pewnym. – CommaToast

+0

W porządku Przetestowałem kilka innych opcji konfiguracji zwijania, ale bez względu na to, co próbuję, otrzymujemy te same 200 sekund i na zewnątrz. O ile nie zmniejszę rozmiaru zapytania, w którym to przypadku zaczyna spadać poniżej 200 sekund. To, co ty i Iserni wydaje ci się bardzo prawdopodobne, jest oparte na przewadze dowodów. : D – CommaToast

+0

BTW dla rekordu, próbowałem wget zamiast curl, tylko dla pewności. Ten sam problem. I każdy możliwy argument curl. – CommaToast

1

Czy próbowali za pomocą set_time_limit w PHP

http://php.net/manual/en/function.set-time-limit.php

Domyślnym dla PHP jest zwykle 30 sekund i znaleźć w php.ini


Dla konfiguracji Apache zobaczyć timeout, keepalive, keepalivetimeout i maxkeepaliverequests

http://users.cis.fiu.edu/~downeyt/cgs4854/timeout


zobaczyć również http://www.devside.net/wamp-server/apache-and-php-limits-and-timeouts dla dobrego ogólnego przewodnika.

Byłem w stanie uruchamiać żądania z apache i php przez 15 minut, więc możesz je przedłużyć na dość długi czas.

+0

Próbowałem set_time_limit, ale to zostanie przesłonięte automatycznie przez max_execution_time, które ustawiłem na 300000. Jeśli chodzi o Apache, limit czasu jest ustawiony na 300, więc nie może być problem.Tymczasem keepalivetimeout ma tylko związek z żądaniami, które przychodzą do apache z zewnątrz. Mój skrypt używa CURL w PHP, aby wysłać żądanie, ale domyślnie CURL nie określa limitu czasu oczekiwania na odpowiedź. Otrzymuje odpowiedź 200 OK na żądanie POST, ale po 200 sekundach otrzymuje pusty łańcuch jako odpowiedź. Czemu? W moim systemie nie ma pliku konfiguracyjnego curl. – CommaToast

+0

Istnieje domyślny limit czasu dla zwijania, ustawiony na 300 sekund (nie 200), można go zastąpić za pomocą 'curl_setopt ($ ch, CURLOPT_TIMEOUT, 400);'. W każdym razie, jeśli został osiągnięty limit czasu, 'curl_exec' zwróci' false', a nie pustą odpowiedź serwera. –

0

Upewnij się, że używasz pełnej ścieżki URL do zewnętrznego źródła, do którego próbujesz się dostać (ponieważ nie możemy tego zweryfikować na przykładzie Twojego kodu), a co ważniejsze, upewnij się, że twoja komenda cron działa ze ścieżki twojego skryptu przebywa w następujący sposób:

1 1 * * 0 /path/to/your/script php < yourscript.php

Takie postępowanie zapewni wszystko odwołuje ścieżki względnej lokalizacji znajduje się poprawnie.

Należy pamiętać, że podczas testowania czegoś za pośrednictwem przeglądarki, dziennik apache jest w porządku, ale ponieważ jesteś w tekście skryptu, błędy związane z crontab zostaną wysłane do pliku wyjściowego cron.

+0

Nie używamy php CLI do uzyskiwania dostępu do skryptu. Zadanie cron wywołuje zwinięcie, aby uzyskać do niego dostęp. Dane wyjściowe z crona są wysyłane do dev null w naszym pliku crontab. Apache error.log to miejsce, w którym dane wyjściowe dotyczą nas. – CommaToast

+0

Domyślnie cron (natywnie) powinien działać dłużej niż 200 sekund, o ile uzyska początkową odpowiedź uzgadniania, ale możesz podać maksymalną długość limitu czasu (w sekundach) w przypadku, gdy twój serwer jest ustawiony na mniej niż 200. Spróbowałbym również użyć podejścia php cli, zamiast pętli w twoim skrypcie powłoki, ponieważ w gruncie rzeczy zagnieżdżasz wywołania cron zarówno z twojego serwera do samego siebie, jak i do świata zewnętrznego. – RelicScoth

+0

Jak zauważyłem w innych komentarzach, całkowicie ominąłem crona, php i Apache'a i ręcznie uruchomiłem żądanie zwijania (zobacz mój komentarz do odpowiedzi Tyrona). Otrzymałem te same wyniki, co oznacza, że ​​nie ma to nic wspólnego z niczym innym niż zdalnym serwerem. – CommaToast

4

i jest plikiem PHP, który sam zawiera poniższy kod, który z kolei wykorzystuje cURL do wywoływania zdalnego interfejsu API. POST około 10KB z XML i oczekujemy, że otrzymamy około 135KB z powrotem, w porcjach.

Oto kod prośba:

$ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $this->_xml_url); 
    curl_setopt($ch, CURLOPT_POST, true); 
    curl_setopt($ch, CURLOPT_VERBOSE, true); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml')); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_str); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    $output = curl_exec($ch);   
    curl_close($ch); 

Co to jest bardzo prawdopodobne dzieje, że zdalny serwer ($this->_xml_url) jest rzeczywiście równoważenia obciążenia lub inny blok front-end, który ma timeout 200s i wywołuje serwer zaplecza.

Jeśli serwer zaplecza nie odpowiada w określonym przedziale czasu, serwer frontonu zamyka połączenie backendu i kontynuuje wykonywanie (co jest prawdopodobnie niewłaściwe) i wysyła do skryptu odpowiedź "sukces" zawartość, którą ma.

Co to jest nic. W związku z tym długość zawartości wynosi zero.

Najlepszą rzeczą, jaką można zrobić, to rozpoznać problem, sprawdzając długość danych lub zgodność z XML i ponowić lub powiadomić użytkownika. Użyłbym mniejszego limitu czasu niż 200 sekund - powiedzmy 180 sekund - w celu upewnienia się, że ty będzie tym, który podnosił błąd, tj. Zdalny serwer nigdy się nie rozłączy, tyzawiesza się na go.

Spróbuj również powiadamianie opiekunów serwera API w przypadku istnieje jakiś sposób na przyspieszenie żądanie (inny API? Innego kodowania? Możliwość wyników buforowania? Droższe SLA? Itd.)

+0

Z całym szacunkiem, twoja odpowiedź jest również prawidłowa, ale Tyron był technicznie pierwszy i podał sugestię, aby spróbować użyć metody ręcznej do zdiagnozowania problemu i wyeliminowania innych możliwości. Problem z powiadomieniem opiekunów serwerów API jest taki, że ci konkretni faceci nigdy nie odpowiadają na otwarte bilety, nie mają żadnych innych umów SLA, żadnej możliwości buforowania wyników, żadnych innych kodowań. Twoja wskazówka na temat load-balancera może być prawidłowa i złożyłem w niej bilet, aby móc je wskazać, chociaż jestem pewien, że bilet idzie prosto do ich "okrągłego pliku". – CommaToast

+0

To jest absolutnie w porządku. Przejmuję też Tyrona dla zwięzłości! Przykro mi słyszeć o braku wsparcia ze strony opiekunów ... – LSerni

+0

Cóż ... zobaczymy, czy tym razem zrobią coś innego. Jest jak jest. Chciałem tylko upewnić się, że nasz serwer nie był powodem. Dzięki. – CommaToast

4

Czy próbowałeś jawnie ustawienie HTTP Keepalive? coś takiego:

curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Connection: Keep-Alive', 
    'Keep-Alive: 300' 
)); 
+0

Po prostu przetestowałem to, ale to nie rozwiązało problemu. Ale dzięki za pomysł. – CommaToast

+0

Uwaga: włączyłem to również do testu ręcznego. Ta sama rzecz. – CommaToast

Powiązane problemy