I am using ColdFusion 8 and jQuery.
I am working on a page that does several ajax calls via jQuery. Quite frequently, I see an application timeout error on one of the pages that is called via ajax. I do not get the error on every ajax call. I do not get the error on the same call each time.
From what I understand the error is caused by the different pages each trying to access the same application variable at the the same time. I am not sure what is the best approach to resolve the issue.
The code seems to be setting a two second timeout. This seems excessive. Should the cflock be set to readonly? Any other advice?
A timeout occurred while attempting to lock the Application scope.
The error occurred in E:/INETPUB/WWWROOT/DEV/AVCAT/Application.cfm: line 53
Called from E:/INETPUB/WWWROOT/DEV/Application.cfm: line 1
Called from E:/INETPUB/WWWROOT/DEV/Application.cfm: line 53
Called from E:/INETPUB/WWWROOT/DEV/Application.cfm: line 1
51 :
52 : <!---<cfif NOT IsDefined("application.datasource")>--->
53 : <cflock timeout="#CreateTimeSpan(0,0,2,0)#" SCOPE="Application">
The timeout attribute of the cflock tag is expecting seconds. So if you want a two minute timeout period than the timeout attribute should be set to 120. Like this (and I agree that seems excessive):
<cflock timeout="120" SCOPE="Application">
The CreateTimeSpan() function returns a date/time object. I'm not sure how your cflock is interpreting that value for the timeout.
As far as using an exclusive lock versus a readonly lock. If your code is only reading the application scope variables than use a readonly lock. If your code is setting the application scope variables than use an exclusive lock. Using an exclusive lock, which you are using by not specifying the type attribute, will cause that code to be single threaded. That may be your issue there.
Related
I am using CFTHREAD in my ColdFusion application. From what I've read from Ben Nadel (https://www.bennadel.com/blog/2980-terminating-asynchronous-cfthreads-in-coldfusion.htm) ColdFusion only exposes and tracks threads in the current request. In my situation, I am spawning a thread via an ajax call and then providing the user with a cancel button. I was hoping the cancel button could call the terminate method on the thread, but no matter where I store it (application,server,session) ColdFusion always returns an error that it was unable to terminate thread "THREAD_NAME" because "THREAD_NAME" was not spawned.
I know that under the hood, ColdFusion is mostly Java. So I'm hoping that there may be a way. Could anyone either confirm or deny this possibility? Any example of how?
Thanks!
Sorry, I don't have a 50 reputation to comment, so I'll post this as an answer. Recently, I was in the same situation with a CFThread spawned via ajax and I needed to terminate it somehow but was unable to. I had a CFQuery inside a CFLoop that used its datasource in the application scope. So what I came up with was to sign into ColdFusion Administrator and temporarily renaming the datasource which caused the thread to throw a database error. While it was inelegant termination, it served the purpose at the time.
So after seeing this question it got me thinking about a possible workaround if there isn't a known way to accomplish this. Suppose during your thread processing, it tests for the value of a variable in the application/server/session scope. Supposing the value is initially set to "true" and then subsequently set to "false" by another process, when the thread finds the false value, it can terminate gracefully.
Can you?
Yes, but only using internal classes. When the cfthread is created, use the local THREAD_NAME to retrieve a reference to the underlying thread object.
context = getPageContext().getFusionContext();
thread = context.getUserThreadTask( "theLocalTaskName" );
Since the local name can be used by multiple requests, the reference should be stored under a unique name, like a uuid. The reference is actually an instance of an internal class coldfusion.threads.Task. To terminate it, call its cancel() method.
thread.cancel();
Should you?
That's a big question and all depends on what the thread does - how it does it - and how the resources it uses would be affected if the process just stops dead, midstream, with no warning.
The reason is that calling <cfthread action="terminate"..> kills the thread - instantly. CF doesn't care if it's in the middle of a critical section. The server just whacks it with a mallet and stops it cold. The exception logs show that CF does this by invoking Thread.stop()
"Information","cfthread-47","09/07/19","17:10:44","","THREAD_V_2: Terminated"
java.lang.ThreadDeath
at java.base/java.lang.Thread.stop(Thread.java:942)
at coldfusion.thread.Task.cancel(Task.java:257)
at coldfusion.tagext.lang.ThreadTag.terminateThread(ThreadTag.java:345)
at coldfusion.tagext.lang.ThreadTag.doStartTag(ThreadTag.java:204)
The java documentation says stop() method is deprecated because it's inherently unsafe:
Stopping a thread causes it to unlock all the monitors that it has
locked. (The monitors are unlocked as the ThreadDeath exception
propagates up the stack.) If any of the objects previously protected
by these monitors were in an inconsistent state, other threads may now
view these objects in an inconsistent state. Such objects are said to
be damaged. When threads operate on damaged objects, arbitrary
behavior can result. This behavior may be subtle and difficult to
detect, or it may be pronounced. Unlike other unchecked exceptions,
ThreadDeath kills threads silently; thus, the user has no warning that
his program may be corrupted. The corruption can manifest itself at
any time after the actual damage occurs, even hours or days in the
future.
So it's important to consider what a thread actually does, and determine if it's even safe to terminate. For example, if a thread processes a file with FileOpen(), forcibly terminating it might prevent the thread from releasing the handle, leaving the underlying file in a locked state, which is undesirable.
The recommended way of stopping threads in java is with an interrupt(). That's essentially the concept user12031119 described. An interrupt doesn't forcibly kill a thread. It's just a flag that suggests a thread stop processing. Leaving it up to the thread itself to determine when it's safe to exit. That allows threads to finish critical sections or perform any cleanup tasks before terminating. Yes, it requires a little more coding, but the results are much more stable and predictable than with "terminate".
What you will want to do is setup a data structure somewhere like application or session scope that keeps track of threads running that you want to be able to cancel.
Application.cfc OnApplicationStart
<cfset application.cancelThread = {} />
Before entering thread create id and then pass into thread
<cfset threadId = createUUID() />
<cfset application.cancelThread[threadId] = false />
Pass the threadId back to the client for the cancel button. On click of the cancel button pass back the threadId
<cfset application.cancelThread[form.threadId] = true />
During thread execution
<cfif application.cancelThread[threadId]>
<cfabort />
<!--- or your chosen approach to ending the processing --->
</cfif>
If thread reached end then remove thread reference
<cfset structDelete(application.cancelThread, threadId) />
I had previously observed that sqlite db writes are significantly faster when I wrap around an atomic transaction (django) - 0.3 secs without and 0.004 secs with transaction. Hence, I applied transactions throughout my project. Strangely after doing that I started encountering 'database is locked' error which led me to debug it to find out that when an update is running over a transaction (lets call it update A) and when I try to concurrently run another update (B) over a transaction then it fails instantly without waiting for the timeout (5 secs default). But when I tried running update B without transaction, it waited for A to finish and then completed the update. Could anyone provide me with an possible explanation for this which doesn't include removing transactions.
This happens because of these two conditions:
by default transaction.atomic() starts a DEFERRED transaction so no lock is acquired at first
you are reading inside the transaction first and then trying to write
while another process already has a write lock on the database.
For example:
# no lock is acquired here because it executes BEGIN query which
# defaults to BEGIN DEFERRED
with transaction.atomic():
# this acquires read lock on DB
MyModelName.objects.all().first()
# this tries to change read lock to write lock
# but fails because another process is holding a write lock
MyModelName.objects.create(name='Example')
# "OperationalError: database is locked" is raised here
# immediately ignoring the timeout
I am not entirely sure why this happens but I found another post saying that it could be due to a deadlock:
sqlite3 ignores sqlite3_busy_timeout?
So your options are:
Make sure that the write lock is acquired first inside the transaction (i.e. you don't have any read queries before the first write query). You can do this by taking out the read query outside the transaction if possible.
Monkey-patch and force transaction.atomic() to acquire the write lock immediately as described by btimby here:
Fix SQLite "database is locked" problems using "BEGIN IMMEDIATE"
SQLite's timeout can be set with PRAGMA busy_timeout.
The default value is zero, and this settings applies only to the connection (not to the database), so it looks as if not all connections got those 5 seconds.
Ensure that all connections have a proper timeout set by executing that PRAGMA. (And five seconds is dangerous; better use thirty seconds.)
When I try to call a RPC function, which generated from an IDL file by midl tool, it blocks around 20 seconds (at the NdrGetBuffer function) if the IP bound in its RPC_BINDING_HANDLE is unreachable.
I tried to call RpcMgmtSetComTimeout function with RPC_C_BINDING_MIN_TIMEOUT value on its RPC_BINDING_HANDLE before calling that RPC function, but no help, still need to wait ~20 seconds.
Is there any way to shorten the timeout wait time on this case? Thanks a lot!
Elliott
I haven't tried this, but this link suggests that RpcSetBindingOption with RPC_C_OPT_CALL_TIMEOUT should allow you to set the callout.
However, there's still a 20 second timeout on the first call (so the server can start).
I have a very basic app that plugs data into a stored procedure which in turn returns a recordset. I've been experiencing what I thought were 'timeouts'. However, I'm now no longer convinced that this is what is really happening. The reason why is that the DBA and I watched sql server spotlight to see when the stored procedure was finished processing. As soon as the procedure finished processing and returned a recordset, the ColdFusion page returned a 'timeout' error. I'm finding this to be consistent whenever the procedure takes longer than a minute. To prove this, I created a stored procedure with nothing more than this:
BEGIN
WAITFOR DELAY '00:00:45';
SELECT TOP 1000 *
FROM AnyTableName
END
If I run it for 59 seconds I get a result back in ColdFusion. If I change it to one minute:
WAITFOR DELAY '00:01';
I get a cfstoredproc timeout error. I've tried running this in different instances of ColdFusion on the same server, different databases/datasources. Now, what is strange, is that I have other procedures that run longer than a minute and return a result. I've even tried this locally on my desktop with ColdFusion 10 and get the same result. At this point, I'm out of places to look so I'm reaching out for other things to try. I've also increased the timeout in the datasource connections and that didn't help. I even tried ColdFusion 10 with the timeout attribute but no luck there either. What is consistent is that the timeout error is displayed when the query completes.
Also, I tried adding the WAITFOR in cfquery and the same result happened. It worked when set for 59 seconds, but timed out when changed to a minute. I can change the sql to select top 1 and there is no difference in the result.
Per the comments, it looks like your request timeout is set to sixty seconds.
Use cfsetting to extend your timeout to whatever you need.
<cfsetting requesttimeout = "{numberOfSeconds}">
The default timeout for all pages is 60s, you need to change this in the cfadmin if it is not enough, but most pages should not run this long.
Take some time to familiarise yourself with the cfadmin and all its settings to avoid such head scratching.
As stated use cfsetting tag to override for specific pages.
I found this bug report. The question is, "Is that what's happening to me?".
I have a few situations where I do this sort of thing.
<cfthread name="thread1" action="run">
code for thread1
</cfthread>
<cfthread name="thread2" action="run">
code for thread2
</cfthread>
The next one will have an actual name.
<cfthread name="CIMSThread" action="run">
code for CIMSThread
</cfthread>
<cfthread name="thread1,thread2,CIMSThread" action="join"></cfthread>
Every so often, I will get these sorts of exceptions.
"Error","cfthread-638","04/10/13","15:14:14",,"CIMSTHREAD: null"
"Error","jrpp-1215","04/10/13","15:14:22","DWQueries","Error Executing Database
Query.<br><b>Query Of Queries runtime error.</b><br>
Table named CIMSThread.CIMSData was not found in memory. etc"
When it first happened, I ran the applicable report again and got the same type of error on a different thead and eventually got it to run successfully without changing any code or data.
When it first happened, I also thought something bad might be happening in the thread which would cause it to crash, so I did something to force that to happen. However, when I checked the exception log, the error in that thread showed up. In these cases, the exception log shows what's in this post.
We are running Version 9,0,1,274733 and have monitoring turned on.
Am I being affected by the reported bug, or might this be something else?
Reply to Comments
I am not able to reproduce the problem at will. After consulting with my administrator we have turned off monitoring, but the pages are not being run very often. If the errors don't appear for awhile, it won't necessarily prove anything.
The problematic threads contain long running queries. Something I just thought of is that there is a very frequently used page that has never caused an issue. There are two differences between the good page and the problem pages. The good page has runs just two threads and joins them. The problem pages run more than two. Also, the queries on the good page don't take as long to exectute.
For Those Who Suggest A Timeout, It's Not
Here is some code. The query takes about 4 seconds to run.
<cfthread name="ThreadWithTimeOut" action="run">
<cfquery name="thread.x" datasource="dw" timeout="1">
sql deleted
</cfquery>
</cfthread>
<cfthread action="join" name="ThreadWithTimeOut"></cfthread>
<cfdump var="#ThreadWithTimeOut.x#" metainfo="no">
The exception log shows this:
"Error","cfthread-6","04/16/13","14:19:15",,"THREADWITHTIMEOUT:
Error Executing Database Query. **
Error ** (11319) [Red Brick Warehouse JDBC Driver] :
Query timeout (1 seconds) has expired."
coldfusion.tagext.sql.QueryTag$DatabaseQueryException: Error Executing Database Query.
and this:
"Error","jrpp-238","04/16/13","14:19:15","Dan",
"Element X is undefined in THREADWITHTIMEOUT.
That's a different set of exceptions. The previous ones said the thread was null.
look at the error you're getting more closely:
"Error","cfthread-638","04/10/13","15:14:14",,"CIMSTHREAD: null"
"Error","jrpp-1215","04/10/13","15:14:22","DWQueries","Error Executing Database
Query.<br><b>Query Of Queries runtime error.</b><br>
Table named CIMSThread.CIMSData was not found in memory. etc"
From that error I can only assume (because you didn't provide any actual code in your question) that the code in the CIMSTHREAD is raising an error causing the thread to crash and not return any data.
Also from the error (and your question), I can deduct that your thread is querying the database and passing it back.
Now personally I don't know why in the world you're using a thread to query your database. If you need to resort to that because the queries take awhile to execute, then you have bigger problems my friend. I would put the queries being run against the database in a ide attached to the database itself. See if you need to add an index or play with the query somehow so that it returns faster.
Bottom line... I think your problem isn't a cfthread issue, its a timeout issue with your query.