1

I have a application that sends out a few 100k emails each night, so to speed processing added some cfthreads.

This has caused some strange errors, and I've found that a variable created in one thread is being modified by another thread. From the documentation I've read, variables created in one thread should be visible only to that thread?

Made a simple test like so:

<cfthread
    name="thread1"
    action="run">

    <cfsavecontent variable="local.template_body">
        <cfinclude template="templates\6\2\bulletin_template.cfm">
    </cfsavecontent>

    <cfset tmpEmailBody = template_body>
</cfthread>

<cfthread
    name="thread2"
    action="run">

    <cffile action="append"
            file="C:\inetpub\error1.txt"
            output="#tmpEmailBody#">        
</cfthread>

The contents of "tmpEmailBody" successfully get written to the file.

The strange thing is if i remove the cfsavecontent section, and have: <cfset tmpEmailBody = "test">, then the second thread raises and error that tmpEmailBody isnt defined, as I would expect.

Anyone know what's going on here?

Omiron
  • 341
  • 3
  • 15

2 Answers2

0

I believe your running cfthread for the wrong purpose. It seems that the tmpEmailBody in thread 2 is dependent on thread1. You should not run dependent code in separate threads..

A better use of cfthread as pertaining to mailing may be

Thread1 { select Emails from database where emails start from a-m out your list of a-m }

Thread 2 { select Emails from database where emails start from n-z} out your list n-z }

Both of your threads run at the same time. The 2 queries can take place at the same time, but you cant save variables in 1 thread and hope that it matches up your call timing in another thread.

steve
  • 1,490
  • 10
  • 18
  • That code was just to demonstrate behavior that seems to go against the coldfusion documentation. My actual app does similar to what you say, I actually want the variables in my two threads to be completely isolated from each other – Omiron Nov 12 '12 at 20:21
0

The variable tmpEmailBody is being created in the Variables scope, not in a scope that is limited to the thread. The threads will execute in random order and random times, so the error is caused because thread1 hasn't executed its last line before thread2 executes its first line.

All of the normal scopes are not thread safe when using cfthread (as opposed to being thread safe for ColdFusion request threads; aka page threads) If you want to make sure that a variable created/used in one thread is isolated from all other threads then you must use thread scoping. This is officially documented as Using thread data in the ColdFusion documentation.

I would have guessed that you were declaring tmpEmailBody outside of the two threads, but since changing the cfset to a static string gives the expected behaviour I would say there's an "issue" with cfsavecontent and it's writing to the Variables scope instead of thread-local scope, which should be filed as another scoping gotcha.

Since the ColdFusion documentation examples leave a bit to be desired I'll rewrite your code as if you wanted to pass the email body from one thread to the other. You've said this isn't your intended use, but it will show the various thread scopes. The following code copies values into different scopes when it doesn't need to, but done to hopefully make the different scopes more clear. And, as others have stated, the below task is a poor use of threads.

<cfthread
    name="thread1"
    action="run">

    <cfset var template_body = "">

    <cfsavecontent variable="template_body">
        <cfinclude template="templates\6\2\bulletin_template.cfm">
    </cfsavecontent>

    <cfset thread.tmpEmailBody = template_body>
</cfthread>

<cfthread action="join" name="thread1" timeout="60">

<cfset Variables.tmpEmailBody = cfthread["thread1"]tmpEmailBody>

<cfthread
    name="thread2"
    action="run"
    emailBody="#Variables.tmpEmailBody#">

    <cffile action="append"
            file="C:\inetpub\error1.txt"
            output="#Attributes.emailBody#">        
</cfthread>
Community
  • 1
  • 1
nosilleg
  • 2,143
  • 1
  • 22
  • 36
  • In the link you gave to the coldfusion documentation it states "The thread-local scope is an implicit scope that contains variables that are available only to the thread, and exist only for the life of the thread. Any variable that you define inside the cfthread tag body without specifying a scope name prefix is in the thread local scope and cannot be accessed or modified by other threads." So this does seem like it could be a coldfusion bug/gotcha – Omiron Nov 13 '12 at 01:00
  • I think the issue is compounded because your thread exists inside of a function. The `local` scope is function based, and therefore can't be thread-local. What happens if you drop the `local.` from the `cfcontent`? – nosilleg Nov 13 '12 at 08:02