Search code examples
coldfusionsession-variablescoldfusion-9cluster-computingjrun

Coldfusion multiserver cluster session replication - arrays in sessionscope


I'm interested to know if an array stored in session-scope is replecated accross server instances when using multiserver installation of coldfusion9 with e.g. 2 clustered instances running on the same machine with session replication enabled.

I don't know if I understood the documentation correctly:

http://help.adobe.com/en_US/ColdFusion/9.0/Admin/WSc3ff6d0ea77859461172e0811cbf363c31-7ffa.html

It says:

Session replication also ensures that that Session scope variables are replicated across the cluster. However, session replication does not support replication of arrays in Session scope CFCs or variables.

So if I have for example a shopping system which stores the shoppingcart in a session-variable called "cart", which is an array of structs (with quantity and item-ID), this would not be replicated accross the cluster member instances?


Solution

  • If the shopping cart is itself a CFC:

    <cfset session.cart = CreateObject('component','model.objects.shoppingCart') />
    

    if it internally wraps an array of structures, and stores them in SESSION or VARIABLES, it would not work. It would in any other case--but not when being implemented in a ACF9.0 multiserver cluster.

    The solution is to re-design the CFC/Classes for your store so that they:

    1. Internally (within the CFC), do not use the VARIABLES scope to store access to arrays, and

    2. Internally (within the CFC), do not access the SESSION scope directly when reading/writing to arrays.

    You do this by using a Structure instead of an Array (below is a method declared within your shopping cart CFC):

    <cffunction name="addItemToCart" returntype="void">
      <cfargument name="item" type="any" required="true" />
    
      <cfscript>
      var id = arguments.item.getID();
      if (NOT StructKeyExists(VARIABLES.userCart, 'id')
      {
         VARIABLES.userCart[id] = StructNew();
         VARIABLES.userCart[id].qty = 0;
      }
      VARIABLES.userCart[id].item = arguments.item;
      VARIABLES.userCart[id].qty++;
      </cfscript>
    

    In this above example of pseudo-code, VARIABLES.userCart, which is the scope accessible within the confines of the CFC (and shared across its method calls for the life of the CFC) is storing the userCart variable as a Structure instead of an Array. Then, with some finesse, we add new keys to the structure based on the unique id of the shopping cart item, and create a sub-struct: one to hold the actual store item (in the 'item' key) and one to hold/update the quantity (in the 'qty' key).

    Using a structure as your storage mechanism, instead of an array, will allow you to build a CF9 app that is supported in your multiserver cluster, if you decide to instantiate/store CFCs in SESSION.

    So, to summarize:

    <cfset SESSION.myCartItemCount = ArrayNew(1) />
    

    Supported.

    <cfset SESSION.user = CreateObject('component','model.objects.user') />
    

    Supported, if there is no Array storage inside the CFC.

    <cfset SESSION.cart = CreateObject('component','model.objects.cart') />
    

    Not Supported, if there is internal reading/writing to Arrays.

    Change the Arrays to Structures under the hood, and you are good to go.