azureazure-web-app-servicesitefinitysession-affinity

Suppress affinity cookie to force client to another Azure app node


I have a C# web application that uses a component (Progress Telerik Sitefinity CMS) that takes a long time (2 minutes) to initialize. A user who visits the site while in this stage, will be redirected to a page that polls the state every second, until initialization is complete. (This is built-in Sitefinity behavior).

I'm hosting my application within an Azure App Service. If I increase the number of instances (scale up), some of my users end up on the new node while it's still initializing. Problem is, due to the affinity cookie Azure adds, they stay on this node.

I want affinity, except when the site is initializing. In that case, I want to drop the cookie and poll. In that case I get assigned a random node, so an initialzed node is found within seconds.

Question is: how do I achieve this? Much of what happens is handled within Sitefinity, so I resorted to altering content in my global.asax. It doesn't work. I tried to put this in my global.asax.cs:

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    var path = HttpContext.Current.Request.Url.AbsolutePath;
    // "/sitefinity/status" is the page the client is redirected to
    // "/appstatus" is used to poll initialization status
    if (path == "/appstatus" || path == "/sitefinity/status")
    {
        // "ARRAffinity" is the Azure affinity cookie
        Response.Cookies.Remove("ARRAffinity");
        // just removing the cookie didn't work so i tried to override it
        Response.Cookies.Add(new HttpCookie("ARRAffinity", "-") { HttpOnly = true });
        // reportedly, this suppresses cookie adding by Azure
        Response.Headers.Add("ARR-Disable-Session-Affinity", "true");
    };
}

How do I force my client to a different node?

EDIT I think I found (part of) the problem here.

So that's might be the problem. Now to solve it...

EDIT

I followed Vesselin Vassilevs suggestion and added this to my sites configuration file:

<appSettings>
    <add key="sf:AppStatusPageResponseCode" value="503" />
</appSettings>

But because I still incidentally reach the initializing node, I also suppressed the affinity cookie , by altering my global.asax.cs:

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        var httpCode = Response.StatusCode;
        var isRedirectBackFromStatusPage = httpCode == 302 && Request.Url.AbsolutePath == "/sitefinity/status";
        var isFinalSitefinityStatusPoll = httpCode == 404 && Request.Url.AbsolutePath == "/appstatus";
        if (isRedirectBackFromStatusPage || isFinalSitefinityStatusPoll)
        {
            var cookie = Request.Cookies["ARRAffinity"];
            if (cookie != null) Response.Cookies.Add(cookie);
            return;
        }
        if (httpCode != 200 || !Response.ContentType.StartsWith("text/html"))
        {
            Response.Headers.Add("ARR-Disable-Session-Affinity", "true");
        };
    }

Solution

  • Why not disable the arr affinity cookie altogether? Sitefinity backend works fine with no arr cookie and with multiple instances.

    EDIT: We need to tell Azure that the site is not yet ready during the Sitefinity initialization. The problem with that is, that the appStatus page (shown by Sitefinity during init) returns status code 302 and even 200, which makes Azure to believe the site is running ok. I've wrote about this here: https://sitefinitydevelopment.com/blog/sitefinity's-application-status-page-can-cause-you-big-problems.html Depending on your Sitefinity version, you can either implement the custom solution there (manually returning http code 503 during system restart) or set the following setting in the web.config (Sitefinity 9+)

    <add key="sf:AppStatusPageResponseCode" value="503" />