2016-04-29 4 views
4

Je voudrais un peu d'aide pour identifier pourquoi ce code particulier, dans de rares circonstances, produit une condition de concurrence. J'ai trouvé une solution, que je décrirai également, mais je veux vraiment le comprendre.ColdFusion VARIABLES Condition de la course?

Nous avons un système basé sur CMS composé de nombreux modules reposant sur un modèle de boîte à fusibles. Tout passe par un seul index.cfm.

Dans notre fichier Index.cfm, nous créons quelques instances de composants, dont certaines sont bsées sur l'instance APPLICATION.PortalApp créée dans Application.cfc. Je ne suis pas compris ce code parce qu'il est pas tout à fait pertinente:

<cfset REQUEST.ActionHandler = CreateObject("Component", "Components.ActionHandler").init(APPLICATION.PortalApp.Config) /> 
<cfset VARIABLES.Modules = CreateObject("Component", "Components.Modules").init(APPLICATION.PortalApp.Config, REQUEST.ActionHandler.GetModuleList(), REQUEST.ActionHandler.GetSuppressOutput(), REQUEST.ActionHandler.GetRoleList(), REQUEST.ActionHandler.GetAccessList(), REQUEST.ActionHandler.GetMasterRoleList()) /> 

Après instancier ces objets, nous obtenons le contenu des modules sur la page (en fonction de leur « volet »: haut, gauche, milieu, à droite) en appelant un composant PageManager qui est instancié dans le cadre de l'application Application.PortalApp.

<cfsavecontent variable="Variables.Portal_Content.Top"><cfset APPLICATION.PortalApp.PageManager.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 0 ) /></cfsavecontent> 
<cfsavecontent variable="Variables.Portal_Content.Left"><cfset APPLICATION.PortalApp.PageManager.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 1 ) /></cfsavecontent> 
<cfsavecontent variable="Variables.Portal_Content.Middle"><cfset APPLICATION.PortalApp.PageManager.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 2 ) /></cfsavecontent> 
<cfsavecontent variable="Variables.Portal_Content.Right"><cfset APPLICATION.PortalApp.PageManager.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 3 ) /></cfsavecontent> 

PageManager.DisplayContent bascule sur les modules et les enveloppe dans un wrapper. Cependant, à certains points, il y a une condition de course et la fonction cratères et affiche aucun module du tout. Il semble être basé sur VARIABLES.Modules devenant corrompu mais c'est dans la portée VARIABLES qui n'est pas partagée.

Pour résoudre ce problème, nous avons changé le code à ce qui suit:

<!--- If we do not use VARIABLES scope and create a ContentManager, race condition can cause empty modules ---> 
<cfset VARIABLES.CurrPageMgr = CreateObject("Component", "Components.ContentManager").init() /> 

<cfsavecontent variable="Variables.Portal_Content.Top"><cfset VARIABLES.CurrPageMgr.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 0 ) /></cfsavecontent> 
<cfsavecontent variable="Variables.Portal_Content.Left"><cfset VARIABLES.CurrPageMgr.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 1 ) /></cfsavecontent> 
<cfsavecontent variable="Variables.Portal_Content.Middle"><cfset VARIABLES.CurrPageMgr.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 2 ) /></cfsavecontent> 
<cfsavecontent variable="Variables.Portal_Content.Right"><cfset VARIABLES.CurrPageMgr.DisplayContent(SESSION, REQUEST.ActionHandler, VARIABLES.Modules, 3 ) /></cfsavecontent> 

Le DisplayContent de ContentManager est le même texte de fonction exacte que le PageManager.DisplayContent à l'exception sur ContentManager existant uniquement dans VARIABLES portée et PageManager existant dans le cadre de l'APPLICATION.

Cela a été très difficile à reproduire après avoir reçu des rapports de celui-ci. J'ai essentiellement commencé une session de jmeter martelant le serveur de développement aussi dur que possible avec un ensemble de point de rupture basé sur une condition que je savais tirer avec VARIABLES.Module est corrompu. C'était le seul moyen de le reproduire.

Je ne suis pas non plus sûr à 100% que ce correctif fonctionne, mais jusqu'à présent jmeter n'a pas déclenché la condition avec elle en place.

Edit: Par demande, la fonction DisplayContent:

<cffunction name="displayContent" access="public" output="true"> 
    <cfargument name="SessionData" required="yes" type="Struct" /> 
    <cfargument name="ActionHandler" required="yes" type="ActionHandler" /> 
    <cfargument name="Modules" required="yes" type="Modules" /> 
    <cfargument name="Pane" required="yes" type="numeric" /> 
    <cfswitch expression="#Arguments.Pane#"> 
     <cfcase value="1"><cfset Variables.blnPane = ARGUMENTS.Modules.getLeft()></cfcase> 
     <cfcase value="2"><cfset Variables.blnPane = ARGUMENTS.Modules.getCenter()></cfcase> 
     <cfcase value="3"><cfset Variables.blnPane = ARGUMENTS.Modules.getRight()></cfcase> 
     <cfdefaultcase><cfset Variables.blnPane = ARGUMENTS.Modules.getTop()></cfdefaultcase> 
    </cfswitch> 
    <cfif VARIABLES.blnPane> 
     <cfset VARIABLES.qryPaneModules = ARGUMENTS.Modules.GetModulesInPane(Arguments.Pane)> 
     <cfset VARIABLES.aryModulesInPane = ArrayNew(1)> 
     <cfloop query="VARIABLES.qryPaneModules"> 
      <cfset VARIABLES.blnResult = ArrayAppend(aryModulesInPane,VARIABLES.qryPaneModules.MOD_SYS_NR)> 
     </cfloop> 
     <cfset VARIABLES.Template = "../CustomTags/Portalv#ARGUMENTS.SessionData.intPortalVersion#/DisplayModuleAlternate.cfm"> 
     <cfif Arguments.ActionHandler.GetDocumentType() EQ 3> 
      <cfset VARIABLES.Template = "../CustomTags/Portalv#ARGUMENTS.SessionData.intPortalVersion#/DisplayXMLModule.cfm"> 
     </cfif> 
     <cfif VARIABLES.qryPaneModules.recordcount GT 0> 
      <cfloop index="VARIABLES.modLoop" from="1" to="#ArrayLen(VARIABLES.aryModulesInPane)#"> 
       <cfparam name="VARIABLES.aryModulesInPane[VARIABLES.modLoop]" default="0"> 
       <cfset VARIABLES.objModuleInfo = ARGUMENTS.Modules.GetModuleInfo(VARIABLES.aryModulesInPane[VARIABLES.modLoop], ARGUMENTS.Modules.GetModules()) /> 
       <cfif NOT IsNumeric(VARIABLES.objModuleInfo.intModuleID)> 
        <cfset VARIABLES.objModuleInfo.intModuleID = 0 > 
       </cfif> 
       <cfmodule template="#VARIABLES.Template#" 
        ModuleID="#VARIABLES.objModuleInfo.intModuleID#" 
        ModuleName="#VARIABLES.objModuleInfo.strModuleName#" 
        SecurityLevel="#VARIABLES.objModuleInfo.intRoleTypeID#" 
        ModuleDSN="#VARIABLES.objModuleInfo.strModDBDSN#" 
        ModuleUserName="#VARIABLES.objModuleInfo.strModDBUserID#" 
        ModulePassword="#VARIABLES.objModuleInfo.strModDBPassword#" 
        AlternateFunctionID="#VARIABLES.objModuleInfo.intAlternateFunctionID#" 
        AlternateFunctionName="#VARIABLES.objModuleInfo.strAlternateFunctionName#" 
        InstructionFileID="#VARIABLES.objModuleInfo.intManualID#" 
        ModuleOps="#VARIABLES.objModuleInfo.blnModuleOps#" 
        ModuleSource="#VARIABLES.objModuleInfo.strModuleSource#" 
        ItemID="#VARIABLES.objModuleInfo.intModItemID#" 
        AutoLoginID="#VARIABLES.objModuleInfo.intAutoLoginCategoryID#" 
        IPS_objPortalSessionData="#ARGUMENTS.SessionData#" 
        ModuleList="#ARGUMENTS.ActionHandler.GetModuleList_SingleRecord(VARIABLES.objModuleInfo.intModuleID)#" 
        ModulesComponent="#ARGUMENTS..Modules#" 
        ControlHeaderIR = "#VARIABLES.objModuleInfo.blnControlHeaderIR#" 
        BorderIR = "#VARIABLES.objModuleInfo.blnBorderIR#" 
        IPS_strPortalRoot = "#VARIABLES.IPS_strPortalRoot#" 
        IPS_strPortalURL = "#VARIABLES.IPS_strPortalURL#" 
        Wrapper = "#Arguments.ActionHandler.getWrapper()#" 
        Definition = "#VARIABLES.objModuleInfo.strModuleDef#" 
        Category = "#VARIABLES.objModuleInfo.strModuleCat#" 
        aryModulesInPane = "#VARIABLES.aryModulesInPane#" 
        blnLockIR = "#VARIABLES.objModuleInfo.blnLockIR#" 
        strMessageTE = "#VARIABLES.objModuleInfo.strMessageTE#" > 

      </cfloop> 
     </cfif> 
    </cfif> 
</cffunction> 
+1

Il semble probable qu'il y ait quelque chose (variable non-délimitée ou verrou manquant, etc.) dans 'DisplayContent' qui cause le problème, d'autant plus que lorsque vous le créez par requête, il semble le réparer. Aurait besoin de voir le code 'DisplayContent' pour approfondir. –

+0

@JohnWhish Ajout de la fonction ... – Brad

+1

Si ce composant est stocké dans la portée de l'application, alors stocker quelque chose dans sa portée 'variables' est essentiellement le même que le stocker dans la portée de l'application. – Leigh

Répondre

1

Utilisation du champ VARIABLES dans la fonction DisplayContent du composant PageManager (qui a été instancié dans le cadre de l'application, ainsi partagée), était la question. La portée VARIABLES serait partagée dans ce cas conduisant à des conditions de course. En dehors de la duplication de cette fonction dans un autre composant et de son instanciation dans la zone VARIABLES du fichier index.cfm, vous pouvez également passer de la portée VARIABLES de la fonction DisplayContent à la portée LOCAL (en supposant que vous n'ayez pas besoin d'accéder à ces variables en dehors de la fonction). Les deux moyens ont empêché la condition de course de réapparaître lors d'un test de stress avec jmeter.

+1

Oui. L'écriture dans la portée 'variables' rend l'état du composant * ful *, et donc soumis à des conditions de concurrence lorsqu'il est stocké dans une application partagée comme la portée, car la portée' variables' est maintenant accessible à plusieurs threads. En règle générale, seuls les composants sans état doivent être stockés dans des étendues partagées. Pour les composants state * ful *, vous devez généralement créer une instance distincte au niveau de la requête afin que les variables ne soient pas partagées/accessibles aux autres demandes. – Leigh