--
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEBwyM%3DddD%3DbCr5WhzO0ngGDc7e-McoNAsB0ag8s8iv69DQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEBwyM%3DddD%3DbCr5WhzO0ngGDc7e-McoNAsB0ag8s8iv69DQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
|
|
CONFIDENTIAL AND PRIVILEGED - This e-mail and any attachment is intended solely for the addressee, is strictly confidential and may also be subject to legal, professional or other privilege or may be protected by work product immunity or other legal rules. If you are not the addressee please do not read, print, re-transmit, store or act in reliance on it or any attachments. Instead, please email it back to the sender and then immediately permanently delete it. Pixl8 Interactive Ltd Registered in England. Registered number: 04336501. Registered office: 8 Spur Road, Cosham, Portsmouth, Hampshire, PO6 3EB |
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAH368SRjD%2B_BHLvEFAB8qEbjEg-EH-PSO0NxmsnYkBZA1GzdbQ%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAEYvUxmtmDv1SNFFJjjnfGduXZciPrGfe4aKQHRr8jvm-1akAQ%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEBy_rVfTYOnh4%3DbX6A_txCu7KtwV8p6XBxU5b4T0NxxqjQ%40mail.gmail.com.
executeWithin( timespan, executionClosure, timeoutExceptionHandlingClosure );
// stuff to do when complete w/ no timeoutI like the general idea of arbitrary timeouts. Not sure on the syntax though. How about something along these lines?timeout timespan=mytimeout {a bunch of code} ontimeout {// stuff to do when the timeout is hit} oncomplete {}
On Thursday, 12 February 2015 23:23:35 UTC+13, Dominic Watson wrote:executeWithin( timespan, executionClosure, timeoutExceptionHandlingClosure );This. Not the version Micha suggested, which was goddawful. Any syntax suggestion like Micha's is going to result in me thinking of this: http://blog.adamcameron.me/2015/01/cfml-evolution-of-functionality.html
That said, there's two different things afoot here.Secondly, there's this "code timeout" idea which you're discussing the solution for above. I think you've nailed the syntax above, Dom.
Firstly there's recovery from out-of-control requests. I don't think the current solutions are correct, but unlike Alan BlueDragon, I do think it's the job of the system to pay attention to. And unlike Railo/Lucee, I think it's the application's job to possibly tidy-up after.
I've not given this much thought, but I was wondering about an additional handler in the application framework (in Application.cfc, but might need to be in Server.cfc?):public boolean function onTimeoutReached(context);
Returning true from this would let the request continue, at least for another timeout period, before firing onTimeoutReached() again. Returning false would end the request (onRequestEnd() fires). Raising an exception in this would cause onError() to fire.
I dunno what the context argument would contain, but something that would allow the handler to possibly deal with whatever is going on at the time the timeout was reached.
Thoughts?--Adam
--
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/6c80ab26-435f-4a9a-9de1-47722060c2b0%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEByB6HsDcxKHz88FYOtXbv1Mu6X7CBEeiSCBRD-3ct5tww%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAEYvUx%3DnhW5F62_rcnZHSacOD%3D1C1NH_-zc%3D0-UtKrx%3DXbW08w%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEBxe%3D1R%3DD3wYngaOyzQZLoRncAOp7yMLvB6h2bSwTKZ61w%40mail.gmail.com.
@Micha, for me, I don't like the idea of having a return value from the timeout
- especially not in having to define the variable that gets the result in an attribute.
What would be in that returned value? Just success / failure?
If so, either throwing an error or having some try / catch style syntax would remain consistent and give a cleaner syntax I think.
I would also argue that for consistency, both a tag and a function could/should be implemented. For the function with closure, you would rightly need to ensure that other functionality across the board was using a similar syntax and that you had nailed the roadmap for that so as to keep consistency. And FWIW, the function name executeWithin() is not clear enough, perhaps executeWithinTimeout( timeout=485, code=closure ).
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAEYvUxkP2D3srM_3NjkdW8YMYswO%3DR8BaFm1PzxE3q1g58b-_w%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEBzPnXsZgv4kB66ANKeyUSy4U5PjiwsHBb0aH5FUgAFsrw%40mail.gmail.com.
Gotcha @micha. I think my main gripe though is that if you are to build new features, use the best bits of the existing syntax and not continue with the odd ones (i.e. declaring return values in attributes, especially when that return value may not really be needed).
Re sending the wrong message on timeouts - programmers can set the request timeout per request, why should they not then be able to decide what to do when that limit has been reached *before* the execution is interrupted? Indeed, if onError() is already invoked on request timeout, could you not just as easily invoke a more specific onRequestTimeout()?
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAEYvUxk4HQgeg15MRk8wTwZf4rXTuF1sTbSBSCvQvGs0pbAZvg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAEYvUx%3DsyR4qCAhTmXjX9-YcKqMHrSNqfyMXo4wri7CbiCk4Zg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAG%2BEEBwHuspuMKbqVj%3DsMtvD%3DdcH1BJZt02VN26GyZ462mdBEw%40mail.gmail.com.
component {
public function invokeMethod(invocation) {
var meta = getMetaData(invocation.getTarget());
param name="meta.timeout" default=10;
try (within=meta.timeout) {
return invocation.proceed();
} catch (TimeoutException e) {
// handle the timeout
}
}
}
> try (within=meta.timeout) {
> return invocation.proceed();
> } catch (TimeoutException e) {
> // handle the timeout
> }
^^^^ +1 for 'within'. That reads really naturally.
Igal Sapir
Lucee Core Developer
Lucee.org
--
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/CAEYvUxm6OgaYw4K4cpu88n9VOUQYhybRoUAD6aWODySnYL%2B0BA%40mail.gmail.com.
This. Not the version Micha suggested, which was goddawful. Any syntax suggestion like Micha's is going to result in me thinking of this: http://blog.adamcameron.me/2015/01/cfml-evolution-of-functionality.htmlthanks for the inspiring words ;-)
this is consistent with the current syntax (see cflock), i always try to see the biiger picture and try to be pragmatic in my solutions.
res=timeout(timespan="#createTimeSpan(0,0,0,10)#") {data=getDataFromExtensionProvider();}
i would like to merge script tags with BIFs in the future, but that is an other discussion and i try to not mix things up...In my opionion adding a closure in that case is simply a overhead ...
Firstly there's recovery from out-of-control requests. I don't think the current solutions are correct, but unlike Alan BlueDragon, I do think it's the job of the system to pay attention to. And unlike Railo/Lucee, I think it's the application's job to possibly tidy-up after.that is my point, a request timeout has nothing to do with "tidy-up after"it is "hell something is very wrong here, you need to do something! Please let that never ever happen again! Please!"When you have a request timeout in your log you have to solve it, because it can harm your system! You dont deal with it in your code!
When you have rats in your house you try to get rid of them, not make a arragement with them!
public boolean function onTimeoutReached(context);
I dunno what the context argument would contain, but something that would allow the handler to possibly deal with whatever is going on at the time the timeout was reached.
I'm getting mixed messages Micha. "Consistent with the existing syntax". "We want to create a new syntax to move away from the baggage of the old syntax".
@Adam, love the idea of an onRequestTimeout application lifecycle event that might allow some kind of recovery.
That is not about .lucee, that was about a new feature, remember what ever happen, new feature are not affected by the dialect.
still any kind of "recovery" from a request timeout is sending the wrong message.
java has extended the try statement to close "closable" object automatically, so doing "2 jobs" with try catch is not uncommon.
On Thursday, 12 February 2015 23:23:35 UTC+13, Dominic Watson wrote:executeWithin( timespan, executionClosure, timeoutExceptionHandlingClosure );
Or 2 group's: 1 for Lucee-CFML (nee Railo) and one for Lucee-New. Most of the angst so far has been due to this confusion.
On Friday, 13 February 2015 14:32:32 UTC+13, Adam Cameron wrote:
On Thursday, 12 February 2015 23:23:35 UTC+13, Dominic Watson wrote:executeWithin( timespan, executionClosure, timeoutExceptionHandlingClosure );Having surveyed all the suggestions made, and kept an open mind about them, I still think this is the most natural, clean approach.
function invokeMethod(invocation) {
try (within=30) { // or timeout
return invocation.proceed();
} catch (TimeoutException e) {
// handle the timeout
}
// vs
// now an extra variable is introduced - potentially wasting memory?
var result = javacast("null","");
executeWithin(createTimespan(0,0,0,30), function() {
result = invocation.proceed();
}, function() {
// handle the timeout
});
return result;
}
try (within=30) { // or timeout
var fileToProcess = fileRead("/path/to/resource");
// process file into the database...
} catch(TimeoutException e) {
// just took way too long...
} catch(MissingFile e) { // or whatever the exception should be in case fileOpen fails...
// file isnt there
} catch(Database e) {
// error inserting records
} finally {
// easy to tell if this gets called if the timeout is reached
}
// vs
executeWithin(createTimeSpan(0,0,0,30), function() {
try {
var fileToProcess = fileRead("/path/to/resource");
// process file into the database...
} catch(MissingFile e) { // or whatever the exception should be in case fileOpen fails...
// file isnt there
} catch(Database e) {
// error inserting records
} finally {
// what about now? does this block execute if execution exceeds the timeout?
}
,function() {
// took way too long...
// handling the timeout here feels unnecessarily disjointed
});
so you should avoid request timeouts at any coast and never ever try to deal with them.
if a request timeout occurs, you need to find out why and solve that problem.
try{
someLockInHere();
someTimeoutInHere();
}catch(Lock e){
}catch(Timeout e){
}
block
timeout=150
throwOnTimeout=true (default - there may be cases where you dont want to throw on timeout)
{
}
Inside the "Request Timeout" thread was a discussion going on that was pointing out that a request timeout cannot be catched by a try/catch, what seems possible in ACF.In my opinion this is a bug in ACF here here is my explanation why:"Like i said, a request timeout is like pulling the plug, i assume you do not pull the plug on your computer when you are done working, this has the risk to destroy open file when they are in a transition. You only pull the plug when the computer is frozen.
With running requests it is exactly the same, a request timeout always comes with the risk to destroy something, maybe the request was just writing a file that then is only halfway done or you have open streams that not get closed properly anymore ...
so you should avoid request timeouts at any coast and never ever try to deal with them.
if a request timeout occurs, you need to find out why and solve that problem.
that is btw exactly the same as caching runtimeexcpetions in java, that smells!"The reason i'm writing all of this is because something else come to my mind we discussed some time ago, sometimes it is maybe impossible to "fix" a code segment that leads to a request timeout. Simply because that code segment, for example, is dealing with external resources, you have no influence on how long it takes for them to get done.I had that problem in the Lucee admin when calling the ExtensionProvider to get information from them. So i did the following (simplified):// call the extension provider (maybe takes some time)thread name="getData" {request.data=getDataFromExtensionProvider();}// give the thread a chance to finishend=getTickCount()*10000;// now + 10 secondsdo {sleep(100);// take a nap}while(getData.status!="completed" && getTickcount()>end); // wait until the thread is done or we waited more than 10 secondsif(getData.status!="completed") return request.data;throw "not able to get data";So the idea is to do a new tag to does exactly this:
timeout timespan="#createTimeSpan(0,0,0,10)#" result="res" {data=getDataFromExtensionProvider();}
if(res.status=="completed") return data;throw "not able to get data";So you have a code block where you can define how long Lucee maximal can spend time on it and stopping only that block if you want.So you can avoid a request timeout by using this tag for time sensitive code fragments.What do you think?Micha
Hi Micha,at first a big thank you that you reraised the topic for open discussion, I really appreciate that. In ACF it was comfortable to simply catch a request timeout, when the "designed" request runtime was blown up to send notifications or update the import log in the db or something else. But I trust your assessment here, because you have clearly more insight about what happens internally on a request timeout. Even more, the proposed solution is even better than catching a request timeout, because you have full control over the timeout in your code block.IF we consider avoiding request timeouts a principle, I guess it should be recommended in the docs (and explained) and marked as a ACF incompatiblity, eg.so you should avoid request timeouts at any coast and never ever try to deal with them.
if a request timeout occurs, you need to find out why and solve that problem.Not sure, are request timeouts automatically captured somewhere or do I need to log them in the onError?
Adam mentioned that the server should clean up resources automatically, does Lucee do that eg. open files on a request timeout.
New syntax! I think try(timeout... is a weak language design, because where you control the timeout and where you want to catch it, is not always the same place - it is similar to the lock:
try{
someLockInHere();
someTimeoutInHere();
}catch(Lock e){
}catch(Timeout e){
}
I would stick with the lock syntax but have found no word as good as "lock" yet. Even some attributes may fit:
block
timeout=150
throwOnTimeout=true (default - there may be cases where you dont want to throw on timeout)
{
}
Could even imagine to integrate attributes for locking, but probably we should KISS.
On the technical side.I remember on ACF where some DB calls didn't even trigger the request timeout. Would the implementation of that feature really be that robust to interrupt everything on timeout and raise an exception? If thats not possible in every case, it would be good if it is documented well.
Cleaning up resources? If I do a fileOpen() and the timeout occurs, would Lucee close the file for me or would I have to do it in the catch?
--
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/edee0d70-0070-4e4c-ae45-cdf9b9b5ed72%40googlegroups.com.
From a functional perspective, the closure syntax makes sense - especially if you're constantly switching between cfscript and javascript. However, comparing the two in the AOP example I gave:
function invokeMethod(invocation) {
// [...]
// now an extra variable is introduced - potentially wasting memory?
var result = javacast("null","");
executeWithin(createTimespan(0,0,0,30), function() {
result = invocation.proceed();
}, function() {
// handle the timeout
});
return result;
}
The closure syntax feels way too verbose and doesn't feel like an actual feature of the language.
It feels like an afterthought. It also deals with the time out as an event, instead of an exception, which is what it should be IMO.
Well that's easily solved if you simply don't write so much code:function invokeMethod(invocation) {
return executeWithin(createTimespan(0,0,0,30), function() {
return invocation.proceed();
}, function() {
// handle the timeout
});
The variation here is that executeWithin() can easily be implemented to return something if that was something that would be useful. It makes a kinda sense, and allows you do be more expedient with your requirement.
One could either specify the event handler for the time out, or if just omitted, then a time out exception is raised, to be handled elsewhere:function invokeMethod(invocation) {
return executeWithin(createTimespan(0,0,0,30), function() {
return invocation.proceed();
});
}You only need to deal with it differently if there's a need to.These two variations are more descriptive of what's actually being coded for, I think.
The closure syntax feels way too verbose and doesn't feel like an actual feature of the language.Odd. Functions taking "closures" already is part of the language. a try/catch with a time out baked into it isn't.
It feels like an afterthought. It also deals with the time out as an event, instead of an exception, which is what it should be IMO.I disagree there. The time out occurring definitely is an event, and this entire discussion is about how to handle that event. That being the case, using an event handler is kinda the natural approach, surely?
I do agree that generally a time out situation is an exceptional circumstance, but clearly we're discussing a situation where that's not automatically the solution. So offering a non-exception-throwing option by implementing an event handler for it... is actually what's being asked for here!
Again, in this situation use the error handling you've already got there. And it separates the concerns of "dealing with code that might run too long", and "handling exceptions". Which are two different things.
function mayTakeAWhile() timeout=30 {} // reads very succinct
try {
mayTakeAWhile();
} catch(Timeout e) {
...
}
// or if you're doing something inline you can use try/timeout
// if timeout is implemented on the function def, then this should follow suit, although I do think try/within is easier on the eyes
try (within/timeout:30) {
} catch(Timeout e) {}
On the other hand, is the exception handling for the missing file / DB error supposed to be part of the code that might time out? It could be! In which case, obviously that does belong in the executeWithin() call too. Not in exception handling which is excluded from the time out.
try (within/timeout:30) { // try doing this task in 30 seconds
} catch (Timeout e) {
// handle the timeout specifically
} catch (<whatever> e) {
// handle a different exception here
} finally {
// will always execute even if a timeout
}
try {
try (within/timeout:30) { ...
} catch (timeout e) {...}
} catch(...) {...}
try (within/timeout:30) {
} catch (any e) {
// handles timeout exceptions here also
}
Still: you're entitled to your preferred approach here. I'm not suggesting you're not. Nor am I suggesting you're intrinsically wrong. However I'm also not finding myself thinking "hey, Jesse's got a point here".
Good discussion though
, and it's encouraged me to better evaluate the viability / suitability of the function-based solution. I like it more now ;-)
--
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/54DE6FDE.5020506%40lucee.org.
For more options, visit https://groups.google.com/d/optout.
Side note, I would say with executeWithin(), it would be a must for it to return the value of whichever callback returns first.
return executeWithin(createTimespan(0,0,0,30), function() {
Agreed - I wrote that poorly, and I'm not sure if I can convey my thoughts on it correctly - however I'll try. I still feel the closure syntax feels too verbose. What I intended to point out was that dealing with timeouts as a concept feels less integrated with the language itself. Sure, it is a built-in function, integrated with the language, but honestly (and expounding on this would be its own thread), when I have the option, I think I would prefer syntax constructs or objects as opposed to procedural functions, especially when I'm dealing with otherwise object-oriented code.
1) [...] an overall request timeout (which apparently cannot be handled gracefully?)
My gut feeling on this is that if you are going to go to the trouble of wrapping a long running block of code, you should be ready to handle it at that point, and not just automatically pass along a different flavor of exception. For that reason, I would probably lean toward the timeout handler being required.
If you intend to not handle the timeout then you should throw the exception. At that point, both ways (closures/trys) are essentially equivalent, only the try syntax is faster for me to read and understand what is going on. Nor do I think its a stretch for someone reading it for the first time to understand it quickly.
However, as always, I can think of alternate scenarios, where you do intend to simply throw an exception. That brings this new thought to mind. Lets say you have a component method that should throw an exception if it takes to long to run. You could either wrap the body in an executeWithin, from which you throw an exception explicitly, or... put the timeout on the function:
function mayTakeAWhile() timeout=30 {} // reads very succinct
try {
mayTakeAWhile();
} catch(Timeout e) {
...
}
// or if you're doing something inline you can use try/timeout
// if timeout is implemented on the function def, then this should follow suit, although I do think try/within is easier on the eyes
try (within/timeout:30) {
} catch(Timeout e) {}
On the other hand, is the exception handling for the missing file / DB error supposed to be part of the code that might time out? It could be! In which case, obviously that does belong in the executeWithin() call too. Not in exception handling which is excluded from the time out.
My point was I saw a possibility of a race condition where a database exception occurs at the same time the timeout occurs, in which case, are the catch/finally blocks allowed to complete? From the way the request timeout currently operates, I'm not sure that it would. If they are allowed to complete - could the timeout handler execute first? Possibly. Are these major blockers - no, just extra things to consider. However, these are non-issues with the try/catch.
Another side note - if you have timeouts integrated in with the try/catch (or function), you can get more pinpoint location of where the timeout occurred - page/line/etc - for you to potentially identify the root cause faster. With executeWithin, all you know is something within the first callback took too long. Maybe you know what it is, but maybe not.
Still: you're entitled to your preferred approach here. I'm not suggesting you're not. Nor am I suggesting you're intrinsically wrong. However I'm also not finding myself thinking "hey, Jesse's got a point here".
I'm wondering if the real Adam Cameron actually wrote that. ;) Perhaps my point is to make sure anything that gets done is fully thought out first - win-win :)
Good discussion though
Agreed :) You are highly respected in the community, myself included, and it has been fun hashing this out.
, and it's encouraged me to better evaluate the viability / suitability of the function-based solution. I like it more now ;-)
I've been told I'm stubborn...I still like the try/catch better, and now I like the function timeout idea better too. :)
I get what you mean, and in general I err towards OO code over procedural where possible too. However I also think cocking around adding new language constructs is something that should be treated with extreme caution.
My challenge here is that I think adding a time out to try/catch is just wrong, so another approach is needed. It's not that I think it's better or worse than a closure-based option (or even the other syntax variation mentioned, which I'll get to), I just think it's absolutely the wrong and a syntactically invalid approach.
Some people would fall back to that "tags without angle brackets in script" syntax for a solution, which - IMO - isn't as bad in theory, however I think the actual syntax variation is lazy and inelegant language design which ought to be phased out of CFML... in favour of a "closure" approach.I dunno if you read my blog or saw my earlier link, but I put my position forward here: http://blog.adamcameron.me/2015/01/cfml-evolution-of-functionality.html
...
My point was I saw a possibility of a race condition where a database exception occurs at the same time the timeout occurs, in which case, are the catch/finally blocks allowed to complete? From the way the request timeout currently operates, I'm not sure that it would. If they are allowed to complete - could the timeout handler execute first? Possibly. Are these major blockers - no, just extra things to consider. However, these are non-issues with the try/catch.Don't follow you here sorry. Try again? (I might just be being thick).
You're inventing a shortcoming here. ...