Skip to main content
Participating Frequently
October 23, 2012
Question

CFINVOKE behaves badly when combined with CFLOCK

  • October 23, 2012
  • 2 replies
  • 1774 views

I am using ColdFusion 9 standard on a 32-bit version Windows Server 2008 virtual machine with 6 GB of RAM.

Since migrating an application from a physical server running CF 8 to this new virtual machine running CF 9, I have experienced a very strange behavior.

I am using the CFINVOKE tag (as a web service) to pull down data.  When the web service code is wrapped in a CFLOCK, the request eventually times out with no response.  It appears that the request is stuck waiting to receive the exclusive lock and the ten second window passes.  If I call the web service directly, bypassing the CFLOCK, the request goes through with no problems.

Why would the combination of these thwo tags cause this problem?

Here is what the code looks like in Application.cfm:

<CFLOCK Name="DataPullIntranet" Type="exclusive" TimeOut="10">

  <CFTRY>

    <CFIF IsDefined("URL.ResetData") or

          Len(Application.MediaTrackerCacheDate) is 0 or

          DateCompare(Now(), Application.MediaTrackerCacheDate, "d") is not 0 or

          Not IsDefined("Application.qHomepageNews")

    >

      <!--- cache frequently used queries --->

      <CFINCLUDE Template="RefreshNews.cfm" />

      <!--- reset cache once a day --->

      <CFSET Application.MediaTrackerCacheDate = Now() />

    </CFIF>

    <!--- likely that lock has timed out, initialize data sets to empty --->

    <CFCATCH>

      <CFSET Application.qHomepageNews = QueryNew("NewsID") />

      <CFSET Application.MediaTrackerCacheDate = Now() />

    </CFCATCH>

  </CFTRY>

</CFLOCK>

Here is the web service code in RefreshNews.cfm:

<!--- cache news --->

<CFINVOKE

  WebService="#Application.MediaTrackerServiceURL#"

  Method="GetNewsForHomepage"

  ReturnVariable="Application.qHomepageNews"

>

  <CFINVOKEARGUMENT Name="Domain" Value="#CGI.Server_Name#" />

</CFINVOKE>

Why would the web service time out when combined with a CFLOCK?  The lock is exclusive, but the data refresh should only be triggered by the first request each day.  The rest of the requests should each receive the exclusive lock one at a time, but bypass all the other code and immediately release the lock.  My server is not pegged at 100%, so it does not seem like there are too many requests waiting to gain the exclusive lock.

Any ideas would be appreciated,

Michael Grove

This topic has been closed for replies.

2 replies

BKBK
Community Expert
Community Expert
October 24, 2012

ColdFusion is just doing as it is told. As you yourself say, when subsequent requests arrive at the lock, they will wait until the lock is released. However, some of the variables which determine the conditions for release(Application.qHomepageNews, Application.MediaTrackerCacheDate) are updated within the lock. This results in the lock's timeout exception never being caught.

In my opinion, that update should be done outside the lock. For example, like this

<CFTRY>

<CFLOCK Name="DataPullIntranet" Type="exclusive" TimeOut="10">

    <CFIF IsDefined("URL.ResetData") or

          Len(Application.MediaTrackerCacheDate) is 0 or

          DateCompare(Now(), Application.MediaTrackerCacheDate, "d") is not 0 or

          Not IsDefined("Application.qHomepageNews")

    >

      <!--- cache frequently used queries --->

      <CFINCLUDE Template="RefreshNews.cfm" />

      <!--- reset cache once a day --->

      <CFSET Application.MediaTrackerCacheDate = Now() />

    </CFIF>

</CFLOCK>

<!--- likely that lock has timed out, initialize data sets to empty --->

<CFCATCH>

<CFSET Application.qHomepageNews = QueryNew("NewsID") />

<CFSET Application.MediaTrackerCacheDate = Now() />

</CFCATCH>

</CFTRY>

Inspiring
October 23, 2012

What is the purpose of the lock?

Participating Frequently
October 23, 2012

The purpose of the lock is to prevent multiple requests from triggering the data refresh at the same time.

Here is a test case:

If 500 requests come in simultaniously at midnight, all 500 will try to trigger the data refresh.  The lock allows the first request to pull the data and the other 499 to wait (10 second timeout).  Once the first request has completed, the other 499 requests will each have their turn with the exclusive lock, but discover that no refresh needs to be done and give up the lock.  I am assuming the other 499 requests release the lock quickly and avoid clogging up the lock queue.

Inspiring
October 24, 2012

Wouldn't it be simpler to schedule the data refresh and leave the web applications out of the equation?