Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • William Pedrick 13 posts 133 karma points
    Nov 15, 2023 @ 16:38
    William Pedrick
    0

    Load Balancing in Azure Web Apps with Umbraco 11

    We are looking to use the load balancing function in Azure Web Apps with our Umbraco 11 system and wanted to see if anyone else in the forum had previously done this.

    My understanding from the following 2 articles is:

    https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/azure-web-apps

    https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/flexible-advanced#explicit-schedulingpublisher-server

    1 - We have to setup 2 branches of code (instead of just 1), e.g.

    Master - Administrator

    Master - Public Facing

    2 - We edit the lines in the appsettings.json file on 'Master - Public Facing' branch to:

    " ""Examine"": { ""LuceneDirectoryFactory"": ""TempFileSystemDirectoryFactory"""

    3 - Create a couple of small classes that implement IServerRoleAccessor one for each of the different server roles:

    "public class SchedulingPublisherServerRoleAccessor : IServerRoleAccessor { public ServerRole CurrentServerRole => ServerRole.SchedulingPublisher; }"

    "public class SubscriberServerRoleAccessor : IServerRoleAccessor { public ServerRole CurrentServerRole => ServerRole.Subscriber; }"

    4 - Replace the default IServerRoleAccessor for the your custom registrars. You'll can do this by using the SetServerRegistrar() extension method on IUmbracoBuilder from a Composer or directly in your startup.cs.

    "// This should be executed on your single SchedulingPublisher server builder.SetServerRegistrar

    "// This should be executed on your Subscriber servers builder.SetServerRegistrar

    I am trying to learn how this works, so that I am able to understand the deployment process; is anyone able to provide (I am not a developer, so have very limited knowledge) any more simplified step-by-step instructions regarding steps 3 and 4, so that I can make these changes in the code myself?

  • Owain Jones 58 posts 388 karma points MVP 4x c-trib
    Nov 28, 2023 @ 17:39
    Owain Jones
    1

    Hi William,

    I usually use an environment variable to toggle the server role:

     public class MyComposer : IComposer
     {
          private readonly string _serverRole;
    
          public Composer()
          {
               var serverRole = Environment.GetEnvironmentVariable("UMBRACO_SERVER_ROLE");
    
               if (serverRole.IsNullOrWhiteSpace() == false)
               {
                    _serverRole = serverRole;
               }
          }
    
          public void Compose(IUmbracoBuilder builder)
          {
               // Explicitly set Server Role
               if (_serverRole.InvariantEquals("SchedulingPublisher"))
               {
                    builder.SetServerRegistrar<SchedulingPublisherServerRoleAccessor>();
               }
               else if (_serverRole.InvariantEquals("Subscriber"))
               {
                    builder.SetServerRegistrar<SubscriberServerRoleAccessor>();
               }
               else if (_serverRole.InvariantEquals("Single"))
               {
                    builder.SetServerRegistrar<SingleServerRoleAccessor>();
               }
          }
     }
    
     public class SchedulingPublisherServerRoleAccessor : IServerRoleAccessor
     {
          public ServerRole CurrentServerRole => ServerRole.SchedulingPublisher;
     }
    
     public class SubscriberServerRoleAccessor : IServerRoleAccessor
     {
          public ServerRole CurrentServerRole => ServerRole.Subscriber;
     }
    

    This class can be placed at the root of your project (alongside the appsettings.json files is fine).

    The UMBRACO_SERVER_ROLE environment variable can then be set via the Web App's app settings in Azure, via the Configuration tab. (Set to SchedulingPublisher for the backoffice app, and Subscriber for the frontends)

    Much easier than having 2 separate branches, as it removes the possibility of a merge accidentally changing the role to something else.

    But if you do need to use 2 separate branches, then you can use the same code, but just remove the if statements and env variable code. e.g:

     public class MyComposer : IComposer
     {
          public void Compose(IUmbracoBuilder builder)
          {
               // Explicitly set Server Role as Scheduling Publisher
               builder.SetServerRegistrar<SchedulingPublisherServerRoleAccessor>();
          }
     }
    
     public class SchedulingPublisherServerRoleAccessor : IServerRoleAccessor
     {
          public ServerRole CurrentServerRole => ServerRole.SchedulingPublisher;
     }
    

    Hope that helps!

  • William Pedrick 13 posts 133 karma points
    Nov 29, 2023 @ 16:27
    William Pedrick
    0

    Thank you Owain, that makes total sense to set the role in the Azure configuration as opposed to having 2 branches of code.

    Apologies for my ignorance (I only understand the basics of how Umbraco works), but essentially I could create a file with solely the code above, place it in the root folder and it would set the roles - as long as I add the configuration in Azure?

    What would the file name need to be called?

    Would it need to be referenced anywhere else?

    Presumably, we would always need at least 1 'Subscriber' Web App, in order for the site to work, e.g. we couldn't have 1 'SchedulingPublisher' Web App and then only turn on 'Subscriber' Web Apps as and when we needed the extra load?

    ... and the 2 types, e.g. 'SchedulingPublisher' and 'Subscriber' would need to be on different App Service Plans in order to get the benefit?

  • Owain Jones 58 posts 388 karma points MVP 4x c-trib
    Nov 29, 2023 @ 18:27
    Owain Jones
    100

    Apologies for my ignorance (I only understand the basics of how Umbraco works), but essentially I could create a file with solely the code above, place it in the root folder and it would set the roles - as long as I add the configuration in Azure?

    No worries! That's correct :)

    Here's a screenshot of one of my projects: Screenshot of my project file structure in Visual Studio

    What would the file name need to be called?

    The file can be named anything, I usually use Composer.cs for my project's main composer.

    Would it need to be referenced anywhere else?

    Nope, as the class extends the IComposer interface, Umbraco should pick it up automatically during boot.

    Here's the docs on composers: https://docs.umbraco.com/umbraco-cms/implementation/composing

    Presumably, we would always need at least 1 'Subscriber' Web App, in order for the site to work, e.g. we couldn't have 1 'SchedulingPublisher' Web App and then only turn on 'Subscriber' Web Apps as and when we needed the extra load?

    I think it would work fine with just a Scheduled Publisher, as all the Server Role does is change how Umbraco handles scheduled tasks, e.g.:

    • SchedulingPublisher
      • Responsible for executing scheduled tasks, e.g. scheduled publishing and unpublishing.
      • This is the one your content editors should use to edit content.
      • Ideally, this should only be used by your content editors but can also serve frontend requests.
    • Subscriber
      • Does not run any scheduled tasks.
      • Should not be used by your content editors.
      • More performant for frontend requests.
      • According to the docs, has Read Only access to the database (I am in doubt if this is actually true, as I had a client's content editor, mistakenly use a frontend app to edit content for almost a year, and nothing bad happened)
    • Single
      • Basically the same as SchedulingPublisher, but only used in a single app, non-load balanced, environments. (I don't know what the technical differences are)

    By default, Umbraco delegates these roles automatically, but as you know, it's recommended to do this manually in a load-balanced environment.

    So in theory, yes you could serve your frontend traffic with your backoffice editing app (the SchedulingPublisher), but it is recommended to keep the editing app and public frontends separate for the best performance. So, I would say, only do this if hosting costs are an issue.

    ... and the 2 types, e.g. 'SchedulingPublisher' and 'Subscriber' would need to be on different App Service Plans in order to get the benefit?

    That would depend on how much traffic you're expecting, but for my clients, we always put the editing app and the frontends on their own separate app service plans for maximum performance.

  • William Pedrick 13 posts 133 karma points
    Nov 29, 2023 @ 22:19
    William Pedrick
    0

    Thank you for your clear breakdown.

    When we deploy the LoadBalancer.cs file with this code, it is providing 6 errors in the logs:

    "C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj" (default target) (1:7) -> (CoreCompile target) -> C:\home\site\repository\PROJECTFOLDER\LoadBalancer.cs(1,28): error CS0246: The type or namespace name 'IComposer' could not be found (are you missing a using directive or an assembly reference?) [C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj] C:\home\site\repository\PROJECTFOLDER\LoadBalancer.cs(5,14): error CS1520: Method must have a return type [C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj] C:\home\site\repository\PROJECTFOLDER\LoadBalancer.cs(33,55): error CS0246: The type or namespace name 'IServerRoleAccessor' could not be found (are you missing a using directive or an assembly reference?) [C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj] C:\home\site\repository\PROJECTFOLDER\LoadBalancer.cs(35,14): error CS0246: The type or namespace name 'ServerRole' could not be found (are you missing a using directive or an assembly reference?) [C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj] C:\home\site\repository\PROJECTFOLDER\LoadBalancer.cs(38,46): error CS0246: The type or namespace name 'IServerRoleAccessor' could not be found (are you missing a using directive or an assembly reference?) [C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj] C:\home\site\repository\PROJECTFOLDER\LoadBalancer.cs(40,14): error CS0246: The type or namespace name 'ServerRole' could not be found (are you missing a using directive or an assembly reference?) [C:\home\site\repository\PROJECTFOLDER\COMPANY.Web.csproj]

  • Owain Jones 58 posts 388 karma points MVP 4x c-trib
    Nov 30, 2023 @ 00:17
    Owain Jones
    0

    Hi William,

    You'll need to add the following usings, to the top of the LoadBalancer.cs file, to load the required assemblies:

    using Umbraco.Cms.Core.Composing;
    using Umbraco.Cms.Core.Sync;
    using Umbraco.Cms.Infrastructure.DependencyInjection;
    

    I believe these are all you'll need, but your IDE should tell you if you need any others :)

  • William Pedrick 13 posts 133 karma points
    Nov 30, 2023 @ 16:08
    William Pedrick
    0

    Thanks Owain. I have added these to the top of the 'LoadBalancer.cs' file, but it is still giving a deployment error.

    I am not sure if it is the done thing on the forum (so apologies if not) but could I pay for your time, to jump on a call and see if you would be able to point me in the right direction of where it is failing?

  • William Pedrick 13 posts 133 karma points
    Dec 06, 2023 @ 13:06
    William Pedrick
    0

    We managed to fix the deployment issues.

    Just 2 other questions if you are able to clarify:

    1 - Typically should the base specification of the server have more compute power on the SchedulingPublisher or the Subscriber?

    2 - If we have a custom domain linking to the Azure Web App, would we setup the Subscriber to point to the frontend domain, e.g. www.SITE.com and the SchedulingPublisher to a different domain - or what is standard practice for this?

  • Owain Jones 58 posts 388 karma points MVP 4x c-trib
    Dec 06, 2023 @ 13:24
    Owain Jones
    0

    Hi William,

    Apologies I missed your previous reply! Glad to hear you got it working!

    1 - Typically should the base specification of the server have more compute power on the SchedulingPublisher or the Subscriber?

    We usually have the SchedulingPublisher and Subscribers on the same tiers, which is usually an S2. (although we're looking into switching to P0v3 as they seem to have the same performance as S2s but cheaper).

    But I don't see any reason why they couldn't be on different tiers if needed.

    2 - If we have a custom domain linking to the Azure Web App, would we setup the Subscriber to point to the frontend domain, e.g. www.SITE.com and the SchedulingPublisher to a different domain - or what is standard practice for this?

    For us, this depends on the needs of the client, but usually, we have the frontend subscriber instances pointing to the live domain and the back office would either be accessed via the default Azure Web App URL or via a subdomain on the live domain (e.g. edit.example.com); We also always lock the actual back-office Web App behind Azure AD.

  • William Pedrick 13 posts 133 karma points
    Dec 06, 2023 @ 14:52
    William Pedrick
    0

    Thank you. That is really helpful!

  • William Pedrick 13 posts 133 karma points
    Dec 16, 2023 @ 08:41
    William Pedrick
    0

    From further reading, it is recommended that for the Lucene/Examine configuration:

    1. The single instance Backoffice Administrative Web App should be set to use SyncedTempFileSystemDirectoryFactory.

    2. The multi-instance Scalable Public Web App should be set to use TempFileSystemDirectoryFactory.

    Source: https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/load-balancing/azure-web-apps

    How do you configure that in the appsettings.json to avoid having to have 2 branches of code?

  • Owain Jones 58 posts 388 karma points MVP 4x c-trib
    Dec 19, 2023 @ 14:30
    Owain Jones
    100

    Hi William,

    You can set this as an AppSetting in the Azure portal, by going to the "Configuration" menu, on your Web App, and adding a new application setting.

    Microsoft Docs: https://learn.microsoft.com/en-us/azure/app-service/configure-common?tabs=portal#configure-app-settings

    Any appsettings.json entry can be set here, you will just need to name it in a double underscores separated format.

    E.g. this:

    {
        "Umbraco": {
            "CMS": {
                "Examine": {
                    "LuceneDirectoryFactory": "SyncedTempFileSystemDirectoryFactory"
                }
            }
        }
    }
    

    Would be set like this:

    Name: Umbraco__CMS__Examine__LuceneDirectoryFactory

    Value: SyncedTempFileSystemDirectoryFactory

    Note: you can also use colons : instead of double underscores __ on Windows Web Apps, but Linux Web Apps only support double underscores.

    You can then use a package like Diplo God Mode or Cultiv Environment Variables Inspector to check if the app setting has been applied correctly.

    Hope that helps! 😄

  • William Pedrick 13 posts 133 karma points
    Dec 19, 2023 @ 16:43
    William Pedrick
    0

    Thank you so much.

Please Sign in or register to post replies

Write your reply to:

Draft