2014-09-30 12 views
9

Ho uno script PHP che invia una richiesta a un'API remota. Se la risposta impiega più di 200 secondi per tornare indietro, nella risposta ottengo solo una lunghezza del contenuto pari a zero. Sto cercando di capire perché sta succedendo.Perché Apache restituisce una lunghezza del contenuto pari a zero dopo 200 secondi a una richiesta POST PHP?

Nel tentativo di risolvere questo problema, ho impostato tutte le variabili concepibili nei file di configurazione di Apache e PHP impostate su un periodo superiore a 300 secondi per combattere questo problema, come raccomandato dalla prima risposta di seguito. Le cose che ho impostato a 300 secondi:

  • Apache timeout
  • Apache KEEP_ALIVE tempo
  • PHP max_reponse_time
  • tempo PHP session.cache_expire
  • PHP max_execution_time

Nonostante che io otteniamo sempre risposte di lunghezza del contenuto pari a zero attorno ai 200 secondi. Tuttavia se impiega meno di 200 secondi il problema non si verifica.

Di seguito viene descritto come è impostato il nostro codice.

Quello che succede è che crontab esegue uno script di shell sul nostro server, che chiama un URI di localhost usando/usr/bin/curl. L'URI localhost è servito da Apache ed è un file PHP che contiene il codice sottostante, che a sua volta usa cURL per chiamare l'API remota. Abbiamo POST circa 10 KB di XML e ci aspettiamo di ricevere circa 135 KB indietro, in blocchi.

Ecco il codice di richiesta:

 $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); 

ho acceso il debug nel nostro registrazione Apache e sotto è ciò che otteniamo. In questo esempio la richiesta è stata inviata alle 19:48:00 e la risposta ritorna alle 19:51:23, poco più di 200 secondi dopo.

* 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 

Vorrei sapere se c'è qualcosa di sbagliato in questo codice o qualcosa forse ho perso nelle impostazioni del server che potrebbero causare la lunghezza del contenuto di tornare a zero dopo 200 secondi.

+0

potrebbe essere correlato allo stato '100 Continua'. Prova a disabilitarlo nella richiesta CURL - 'curl_setopt ($ ch, CURLOPT_HTTPHEADER, array ('Expect:', 'Content-Type: text/xml'));' – Cheery

+2

Penso che il problema non sia al tuo fianco .. relativo all'host remoto che stai inviando dati .. molto probabilmente l'impostazione di timeout dello script del server è 200 secondi .. –

+0

@SyedQarib Sì, come ho contrassegnato nella risposta corretta che sembra estremamente probabile che sia il caso. – CommaToast

risposta

6

Suoni molto simili a un timeout sul server API remoto: prova ad accedervi manualmente ad es. tramite browser o wget.

+0

Penso che tu vinca. Ho provato ad accedere manualmente tramite 'curl -m 1800 -v -S -H" Content-Type: application/xml "--data @ test.xml {MYURI}' e sto avendo gli stessi problemi, senza PHP o Apache coinvolti. Quindi, a meno che non ci sia un'opzione arcana di arricciatura che non sto considerando qui, allora penso che tu abbia ragione - specialmente dopo aver cercato su Google su Microsoft-IIS/7.5, trovo che 200 secondi è il valore che raccomandano per i timeout ... I Non sto dicendo che fosse Microsoft, ma era Microsoft. Il tuo suggerimento di provare ad accedervi manualmente è ciò che mi ha portato ad eliminare un numero sufficiente di altre possibilità per essere sicuro al 99% di questo. – CommaToast

+0

Va bene, ho provato alcune opzioni di configurazione del ricciolo più diverse ma non importa quello che provo, otteniamo gli stessi 200 secondi e fuori. A meno che non riduca la dimensione della mia query, nel qual caso inizia a scendere sotto i 200 secondi. Quello che tu e Iserni sembra altamente probabile sia, quindi, basato sulla preponderanza delle prove. : D – CommaToast

+0

BTW per il record, ho provato wget invece di curl, solo per essere sicuro. Stesso problema. E ogni argomento di ricciolo pensabile. – CommaToast

1

Hai provato a usare set_time_limit in PHP

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

L'impostazione di default per PHP è di solito di 30 secondi e ha trovato nel php.ini


Per la configurazione di Apache vedere timeout, keepalive, keepalivetimeout e maxkeepaliverequests

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


vedere anche http://www.devside.net/wamp-server/apache-and-php-limits-and-timeouts per un buon tutorial generale.

Sono riuscito a eseguire richieste con apache e php per 15 minuti, quindi è possibile estenderlo per un periodo piuttosto lungo.

+0

Ho provato set_time_limit ma questo viene sovrascritto automaticamente da max_execution_time, che ho impostato su 300000. Per quanto riguarda apache, il timeout è impostato su 300, quindi questo non può essere il problema.Nel frattempo keepalivetimeout ha solo a che fare con le richieste che arrivano in apache dall'esterno. Il mio script utilizza CURL in PHP per inviare la richiesta, ma l'impostazione predefinita di CURL non è di impostare alcun limite sul tempo di attesa per la risposta. Ottiene inizialmente una risposta di 200 OK alla richiesta POST ma poi ottiene una stringa vuota come risposta dopo 200 secondi. Perché? Non c'è alcun file di configurazione del ricciolo sul mio sistema da nessuna parte. – CommaToast

+0

C'è un timeout predefinito per arricciatura, impostato su 300 secondi (non 200), è possibile sovrascriverlo usando 'curl_setopt ($ ch, CURLOPT_TIMEOUT, 400);'. Ad ogni modo, se si raggiungesse il timeout del curl, 'curl_exec' restituire' false', non una risposta vuota del server. –

0

Assicurati di utilizzare il percorso url completo della risorsa esterna che stai cercando di raggiungere (poiché non è possibile verificarlo dal tuo esempio di codice) e, cosa più importante, assicurati che il comando cron esegua dal percorso il tuo script risiede in, in questo modo:

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

in questo modo garantirà tutto ciò a cui fa riferimento un percorso posizione relativa si trova in modo corretto.

Ricorda che quando esegui il test di qualcosa tramite il browser, il tuo log di apache va bene, ma dal momento che stai sincronizzando lo script, gli errori relativi a crontab verranno inviati al tuo file di output di cron.

+0

Non usiamo la CLI php per accedere allo script. Il lavoro cron chiama curl per accedervi. L'output di cron viene inviato a dev null nel nostro crontab. Apache error.log è dove l'output va per noi. – CommaToast

+0

Per impostazione predefinita, cron (in modo nativo) deve essere eseguito più di 200 secondi finché ottiene la risposta iniziale di handshake, ma è possibile che si desideri passare una lunghezza massima di timeout (in secondi) nel caso in cui il server sia impostato su meno di 200. Proverei anche ad usare l'approccio php cli, invece di scorrere lo script della shell, dal momento che essenzialmente si annidano le chiamate di cron sia dal proprio server a se stesso, sia dal mondo esterno. – RelicScoth

+0

Come notato in altri commenti, ho aggirato cron, php e Apache interamente, e ho semplicemente eseguito manualmente la richiesta di ricciolo (vedi il mio commento alla risposta di Tyron). Ho ottenuto gli stessi risultati, il che significa che non ha nulla a che fare con nient'altro che il server remoto. – CommaToast

4

ed è un file PHP che contiene il seguente codice, il quale utilizza a sua volta cURL per chiamare l'API remota. Abbiamo POST circa 10 KB di XML e ci aspettiamo di ricevere circa 135 KB indietro, in blocchi.

Ecco il codice di richiesta:

$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); 

Che cosa è molto probabile che sia accadendo è che il server remoto ($this->_xml_url) è in realtà un sistema di bilanciamento del carico o altro blocco di front-end che ha un timeout di 200 secondi e chiama un server di backend.

Se il server di backend non risponde entro il lasso di tempo, il server front-end chiude la connessione di back-end e continua ad eseguire (che è probabilmente la cosa sbagliata da fare) e invia allo script di una risposta "successo" con il contenuto che ha

Quale è niente. Da qui la lunghezza del contenuto pari a zero.

Il meglio che puoi fare è riconoscere il problema controllando la lunghezza dei dati o la conformità XML e riprovare o avvisare l'utente. Userei un timeout inferiore a 200s - diciamo 180s - per essere sicuri che tu sia il che genera l'errore, cioè il server remoto non ti riaggancerà mai, tu riaggancia su lui.

Prova anche notificare i manutentori di server API nel caso in cui ci sia un modo per accelerare la richiesta (API diversa? Codifica differente? Possibilità di risultati caching? SLA più costoso? Ecc)

+0

Con tutto il dovuto rispetto anche la tua risposta è corretta, ma Tyron è stato tecnicamente il primo a dare il suggerimento di provare a utilizzare un metodo manuale per diagnosticare il problema ed eliminare altre possibilità. Il problema con la notifica ai manutentori del server API è che questi tipi particolari non rispondono mai ai ticket aperti, non hanno altri SLA, nessuna possibilità di risultati nella cache, nessun'altra codifica. Il tuo suggerimento circa il bilanciamento del carico potrebbe essere corretto e ho archiviato un biglietto con loro per indovinarli, anche se sono abbastanza sicuro che il biglietto sta andando direttamente al loro "file circolare". – CommaToast

+0

Questo è assolutamente ok. Sto anche uptoting Tyron per concisione! Mi dispiace per la mancanza di supporto dei manutentori ... – LSerni

+0

Beh ... vedremo se fanno qualcosa di diverso questa volta. È quello che è. Volevo solo assicurarmi che il nostro server non fosse il motivo. Grazie. – CommaToast

4

Hai provato in modo esplicito l'impostazione il HTTP Keepalive? qualcosa di simile:

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

Appena testato, questo non risolve il problema. Ma grazie per l'idea. – CommaToast

+0

Nota: l'ho anche incorporato nel mio test manuale. Stessa cosa. – CommaToast

Problemi correlati