2012-05-09 14 views
5

Innanzitutto, imposto le richieste di timeout dopo (secondi) a 20 in CF Admin.Perché una richiesta con un ciclo infinito non viene uccisa dal timeout della richiesta ColdFusion?

Poi eseguire un CFM con una linea come while(true);

La pagina verrà eseguito modo negli ultimi 20 secondi, e il filo è ancora vivo, come ho scritto questo.

Qui di seguito è una fotografia presa con Server Monitor

Thread jrpp-3 request type - TEMPLATE REQUEST 
*Template Path - D:\Projects\infiniteLoop.cfm 
*Request Parameters - {} 
*Request Method - GET 
*Client IP address - 127.0.0.1 
*Thread elapsed time - 322659 milliseconds 

è normale ?? Questa è CF9.0.1., Edizione per sviluppatori. Configurazione multi-istanza, con JRun.

L'unico modo per arrestare il ciclo infinito è riavviare CF.

+2

Henry ... cosa stai facendo all'interno del ciclo infinito. Ci sono alcune cose che anticipano il timeout globale (chiamate db, ftp, cose che richiedono risorse esterne). –

+0

Ragazzi ... questa domanda non fa alcun riferimento a CFTHREAD ... non è sicuro da dove provenga. –

+0

@MarkAKruger Sono in procinto di implementare qualcosa di nuovo. I codici sono ancora instabili. L'ho scritto in CFScript e non mi aspettavo che i codici che finiscono per essere eseguiti all'infinito non vengano uccisi dal Timeout delle richieste di CF. – Henry

risposta

11

I timeout delle richieste in ColdFuison non si comportano nel modo previsto. Il modo in cui viene presentato immagina che ci sia un cane da guardia che controlla per quanto tempo la tua richiesta è stata in esecuzione e la uccide o poco dopo il timeout della richiesta. Ciò che in realtà sembra accadere è che solo quando vengono eseguiti determinati tag CF verifica se il tempo trascorso della richiesta supera il limite impostato. <cfoutput> è uno dei tag in cui viene controllato, motivo per cui si vede spesso il messaggio di timeout superato che punta a un cfoutput, anche se si sa che non può richiedere molto tempo per l'esecuzione.

<cfsetting requesttimeout="5" enableCFoutputOnly="no" /> 

<!--- Looping with a condition <cfloop blamed ---> 
<cfset request.counter=0 /> 
<cfloop condition="true"> 
    <cfset sleep(1000) /> 
    <cfset request.counter=request.counter+1> 

    <cflog file="timeout" text="#request.counter#"> 

    <cfif request.counter GT 8> 
     <cfbreak> 
    </cfif> 

</cfloop> 

<!--- Looping with an index, times out, naming CFLOOP as the offending tag ---> 
<cfloop index="foo" from="1" to="8"> 
    <cfset sleep(1000) /> 
</cfloop> 

<!--- Looping with an index, times out, naming CFOUTPUT as the offending tag ---> 
<cfloop index="foo" from="1" to="8"> 
    <cfset sleep(1000) /> 
    <cfoutput>Hello</cfoutput> 
</cfloop> 


<!--- Same loop, but in script. No timeout warning at all ---> 
<cfscript> 
for(foo=1;foo<=8;foo++){ 
    sleep(1000); 
} 
</cfscript> 

<!--- Same loop, now with WriteOutput() called. Still no timeout ---> 
<cfscript> 
for(foo=1;foo<=8;foo++){ 
    sleep(1000); 
    writeoutput("tick..."); 
} 
</cfscript> 

Il codice sopra mostra alcuni comportamenti strani del timeout della richiesta. Come ha fatto notare Mark Kruger, qualsiasi chiamata a una risorsa esterna non comporterà alcun controllo per il timeout, e suppongo che anche i grandi blocchi di script che stanno eseguendo la propria logica non verranno controllati, lasciando la prossima dichiarazione di output da incolpare.

Se è necessario tracciare il punto in cui il codice è in ritardo e i messaggi di timeout puntano al posto sbagliato, utilizzare la registrazione o il jstack per raccogliere le tracce di stack dal server mentre è in esecuzione il codice con esecuzione prolungata. Prendi alcune tracce dello stack a pochi secondi di distanza, quindi esegui il file di registro tramite Samurai per scoprire cosa sta facendo il codice.

+1

Barny - questa è una risposta fantastica. Lo adoro. Grazie per gli esempi. Sembra una buona scelta per un post sul blog e alcune ulteriori indagini. –

+0

Preferisco la risposta, solo per raccomandare Samurai. (Ma nel complesso un'ottima risposta!) – Sharondio

+0

Grazie mille per la tua indagine! Risultato molto interessante/dispari. Chi avrebbe pensato, lo stesso ciclo, ma in cfscript, non verrebbe controllato rispetto al timeout della richiesta. Questo dovrebbe essere corretto, o documentato da qualche parte ... Stai anche usando CF 9.0.1? Forse dovremmo testarlo contro CF7 o 8 per vedere se è davvero lo stesso risultato. – Henry

2

Sto trovando la stessa cosa di Henry. Ecco il mio codice di prova:

Before thread<br /> 
<cfthread action="run" name="t1"> 
    <cfloop condition="true"> 
     <cfparam name="count" default="0"> 
     <cfset sleep(3000)> 
     <cflog file="cfthreadTest" text="Log entry #++count#"> 
    </cfloop> 
</cfthread> 
After thread<br /> 

La mia richiesta di timeout è impostato su 20 sec in CFAdmin, e questa discussione è stata ora in esecuzione per 15 minuti. Detto questo, una discussione non è "una richiesta", quindi non sono sicuro che mi aspetterei che rispetti il ​​timeout della richiesta. Non c'è nulla di documentato che riesca a trovare che suggerisce che dovrebbe rispettare il timeout della richiesta. Detto questo ... avere un modo di uccidere un thread sarebbe "a portata di mano".

Immagino che questa sia solo una "risposta" nel contesto in cui non penso che le tue aspettative siano corrette in quanto ti aspetti che rispetti il ​​timeout della richiesta.

+0

Thx per la risposta, ma non avrei dovuto includere la parola "thread" nel titolo, poiché non ho usato affatto cfthread. Domanda aggiornata. – Henry

+0

OK, beh in tal caso non si può andare oltre la risposta di @ barnyr. –

2

Quello che hai descritto è un comportamento purtroppo previsto quando conosci i vincoli del timeout della richiesta di controllo in ColdFusion. (Concesso, non dovrebbe essere il comportamento previsto.)

C'è un lungo blog post di Charlie Arehart che copre problemi di timeout. Una sezione è intitolata "CF controlla l'ora all'inizio della prossima operazione, ma purtroppo solo su alcuni tag". Sfortunatamente cfscript non è uno di quelli, e il timeout non verrà controllato con puro codice di script.Tuttavia, uno dei tag che attiva un controllo di timeout è cfoutput e con tale conoscenza è possibile rendere il timeout della richiesta di rispetto del codice basato su script. È comunque un processo manuale in cui devi decidere da solo dove dovresti controllare il timeout.

<cffunction name="cf_checkRequestTimeout" access="public" output="false" returntype="void" hint="Force CF to check if the request has timed out."> 

    <!--- CF checks Request timeout on cfoutput tag use. ---> 
    <cfoutput></cfoutput> 

</cffunction> 

<cfscript> 
    for(foo=1;foo<=61;foo++){ 
     sleep(1000); 
     cf_checkRequestTimeout(); 
    } 
</cfscript> 

L'errore generato sarà colpa linea 4, che è fuorviante, ma lo stacktrace mostrerà che la funzione è stata chiamata dalla linea 11, che poi ti permette di sapere quale porzione di codice scaduta. Ovviamente la granularità di tale conoscenza si basa sulla frequenza di controllo del timeout.

Il cf_checkRequestTimeout (non checkRequestTimeout perché è una funzione CF interna non documentato) può essere chiamato al di fuori della cfscript pure, quindi, se, ad esempio, si dispone di un cfquery pensi sta causando problemi di timeout allora si può mettere la chiamata cf_checkRequestTimeout dopo la cfquery e ottenere errori di timeout in cui dovrebbero essere invece di eseguire l'esecuzione del codice.

+0

@Henry Ottenere la richiesta di timeout e capire cosa stava accadendo per rendere il timeout della richiesta sono due cose diverse. Questa risposta riguarda solo il verificarsi del timeout. Dici "che invoca il lancio" intendi quale iterazione del loop? Dovresti aggiungere una logica in più per capirlo. – nosilleg

Problemi correlati