Make your inriver Connector Compatible with Optimizely DXCS

VP, Enterprise Platforms
Valtech

17 julio, 2018

Optimizely Digital Experience Cloud Service (DXCS) relies on Microsoft Azure, where the infrastructure is based on the concept of automatic scaling. It means, any Azure Web-App running through DXCS can clone itself, to accommodate load in peak situations, or to mitigate failures. It does bring a great amount of benefits! It though also require you to think twice when installing pre-built data connectors, especially in scenarios where session state is used inside them.

What’s the issue – a real world example?

We frequently rely on inriver PIM during enterprise Episerver Commerce implementation, and has therefore been around the block more than a few times. inriver do provide a pre-built connector for Episerver Commerce, which eases the integration between inriver PIM and the Episerver Catalog. If you’re using the inriver PIM connector in scenarios involving scale-able Azure Web-Apps, you need to be aware of the internal use of session state. inriver does by default rely on session state to keep track of it’s data import progress. Not having this in mind in an automatically scaling infrastructure quickly creates data inconsistency issues.inriver infrastructure example

Above animation illustrates how inriver might get the idea that the data import has finalized. It is caused by the “Is Importing” session state not being shared across the set of Web-App instances. It can quickly cause multiple imports to happen in parallel, driving great data integrity issues.

 

What’s the solution – an agnostic explanation

Relying on session state in scale-able infrastructures are never ideal, and moving away from persisting any kind of state in memory would be the best solution. Given it sometimes is out of our control, like in above example where we rely on vendor architected code, there are often ways of working around it. Note: Fixing requires you get access to the vendor source code, or that you issue a pull request against their open source code repository.

 

Episerver do by default enable session affinity, which relies on a cookie technology to aid people or connections who need to stay with a certain instance of Web-App in Microsoft Azure. The reason for this is that we strive for statelessness, but are sometimes not able to achieve it – e.g. due to vendor incompatibility.

 

So what’s the issue, you might say? Microsoft Azure’s implementation of session affinity is not by default supported by RESTful integrations, relying on e.g. HttpClient. It does require you to manage it yourself, which often are done by consistently re-using the response cookies issued across multiple requests. If you look at any Episerver solution running in Digital Experience Cloud Service, you will notice a persisted “ARRAffinity” cookie, which depicts what Web-App instance you’re married too right now. Carrying that over from request to request ensures your system communicates with the same instance, irregardless of the number of instances running in parallel.

 

What’s the solution – an inriver explanation

inriver hosts open source repositories for all of their connectors, which makes integration and root cause analysis a breeze. Having access to the raw code also enables us, as good partners, to help inriver re-mediate issues we face during client implementations.

 

Based on above explanation, we need to modify the generic RestEndpoint<T> implementation, taking responsibility of the communication with the Episerver APIs. 

public string Post(T message)

{

    var uri = new Uri(GetUrl());




    CookieContainer cookies = new CookieContainer();

    HttpClientHandler handler = new HttpClientHandler();

    handler.CookieContainer = cookies;




    var client = new HttpClient(handler);

    

    #region Prepare client

    

    //Removed inriver code for readability

    

    #end region

    

    var response = client.PostAsJsonAsync(uri.PathAndQuery, message).Result;

    

    if (response.IsSuccessStatusCode)

    {

        // Parse the response body. Blocking!

        var resp = response.Content.ReadAsAsync<string>().Result;

        

        var endpoint = new RestEndpoint<string>(_settingsDictionary, "IsImporting");




        while (resp == "importing")

            resp = endpoint.Get(cookies);

        

        if (String.IsNullOrEmpty(resp))

            return String.Empty;

        

        if (resp.StartsWith("ERROR"))

            Integration.Logging.IntegrationLogger.Write(LogLevel.Error, resp);

        

        return resp;

    }

    throw new HttpRequestException(errorMsg);

}










public string Get(CookieContainer cookieContainer)

{

    var uri = new Uri(GetUrl());

    HttpClientHandler handler = new HttpClientHandler();

    handler.CookieContainer = cookieContainer;




    var client = new HttpClient(handler);

    #region Prepare client

    //Removed code for readability

    #end region

    

    var response = client.GetAsync(uri.PathAndQuery).Result;




    if (response.IsSuccessStatusCode)

    {

        // Parse the response body. Blocking!

        var resp = response.Content.ReadAsAsync<string>().Result;




        return resp;




    }

    else

    {

        throw new HttpRequestException(errorMsg);

    }

}

Please note – we’ve modified the code to make it more readable. It does not include smaller inriver specific implementation details irrelevant to this blog post.

We hope you will find these insights beneficial, when working on integrations to your Microsoft Azure powered Episerver solution. Happy architecting!

 

Original article was posted on Episerver Fellow: http://fellow.aagaardrasmussen.dk/2018/07/17/make-your-inriver-connector-compatible-with-episerver-dxcs/

Contáctanos

Reinventemos el futuro