3

I have a loop that calls a cfcomponent object.

    <cfset queue_list = "1,2,3">        
    <cfloop list="#queue_list#" index="z">  
                <cfset args = StructNew()>
                <cfset args.group_num = z>          
<cfset args.client_id = 1>          
                <cfset processdownloads = downloader.ProcessDownload(argumentCollection=args)>
            </cfloop>

The component has the following function:

    <cffunction name="ProcessDownload" access="public" output="false">
        <cfargument name="group_num" type="numeric" required="yes">                     
        <cfargument name="client_id" type="numeric" required="yes">                     

        <cfset variables = arguments>

        <cfthread action="RUN" name="download_#variables.client_id#_#variables.group_num#" priority="high">

                    <cffile action="WRITE" file="#expandpath('download\download_in_process\')##variables.group_num#.json" output="#variables.group_num#">           

</cfthread>

</cffunction>

When I run it I receive the following error:

Attribute validation error for the cfthread tag. Thread with name DOWNLOAD_4003_3 could not be created. Thread names must be unique within a page.
The error occurred on line 29.

I have no idea why but it seems to be running twice. Should it not be generating a new thread with a unique thread name, thus avoiding the tread name conflict?

Jeff Shain
  • 767
  • 3
  • 9
  • 21
  • 1
    *``* Without testing the code, it looks like that *might* overwrite the system scope `VARIABLES` - which could definitely cause unexpected behavior... (Though why reassign at all? Any reason you cannot just use the `arguments` scope to reference the variable names?) – Leigh Feb 24 '15 at 21:49
  • Also, if you are not passing client_id in as an arugment, you may have trouble with concurrent users. – Dan Bracuk Feb 24 '15 at 22:20
  • CFTHREAD can't access the argument scope, it appears. Also Dan, I am passing in the client_id, I just didn't include it in the code. (simplified it for example) – Jeff Shain Feb 25 '15 at 00:04

2 Answers2

3

Pass the group_num in as an attribute so you can access it internally without having issues with the variables scope being overwritten.

<cfthread action="RUN" name="download_#arguments.client_id#_#arguments.group_num#" priority="high" group_num="#arguments.group_num#">
    <cffile action="WRITE" file="#expandpath('download\download_in_process\')##attributes.group_num#.json" output="#attributes.group_num#">           
</cfthread>

Everyone else is right, the issue is your variables scope. What is happening is each loop is overwriting the variables scope, so when the thread is being created, it getting the thread name from variable scope, which is already set to 3... so all three threads might try and be set to the same name.

Can you name it using arguments? If not... you could use local. for the name and passing the info into the CFThread Creation.

You are correct about inside a component, you cannot access arguments etc, which behaves very differently from outside of a component.

Ben Nadel wrote a nice post about these issues http://www.bennadel.com/blog/2215-an-experiment-in-passing-variables-into-a-cfthread-tag-by-reference.htm

Ben for the Win as usual.

Gavin Pickin
  • 742
  • 3
  • 7
0

It's likely because your CFC code is not thread-safe.

This:

<cfset variables = arguments>

Copies your function's arguments into the object's shared scope. If the downloader object is shared across requests, then each request is going to be using the other one's values.

Why are you copying your arguments into the objects variables scope? That seems like an odd thing to do.

Adam Cameron
  • 29,677
  • 4
  • 37
  • 78
  • Well the CFTHREAD can't seem to access the arguments scope, I'm just trying to get the arguments passed into that function into the cfthread itself. – Jeff Shain Feb 25 '15 at 00:03
  • 3
    Ah. Gavin's gotcha, but anything you need in the thread needs to be passed as attributes of the `` tag. – Adam Cameron Feb 25 '15 at 01:07