Deploy and scale an Orleans app on Azure

In this quickstart, you deploy and scale an Orleans URL shortener app on Azure Container Apps. The app allows users to submit a full URL to the app, which returns a shortened version they can share with others to direct them to the original site. Orleans and Azure provide the scalability features necessary to host high traffic apps like URL shorteners. Orleans is also compatible with any other hosting service that supports .NET.

At the end of this quickstart, you have a scalable app running in Azure to provide URL shortener functionality. Along the way you learn to:

  • Pull and Azure Developer CLI template
  • Deploy an Orleans app to Azure
  • Scale the app to multiple instances

Prerequisites

Get and deploy the sample application

The sample application is available as an Azure Developer CLI template. Through this quickstart; you pull the template application, deploy the template and sample code to Azure, change the template to implement your preferred persistence grain, deploy the necessary resources, and then deploy the final application.

  1. Open a terminal in an empty directory.

  2. Authenticate to the Azure Developer CLI using azd auth login. Follow the steps specified by the tool to authenticate to the CLI using your preferred Azure credentials.

    azd auth login
    
  3. Get the sample application using the AZD template orleans-url-shortener and the azd init command.

    azd init --template orleans-url-shortener
    
  4. During initialization, configure a unique environment name.

    Tip

    The environment name will also be used as the target resource group name. For this quickstart, consider using msdocs-orleans-url-shortener.

  5. Deploy the Azure Cosmos DB for NoSQL account using azd up. The Bicep templates also deploy a sample web application.

    azd up
    
  6. During the provisioning process, select your subscription and desired location. Wait for the provisioning and deployment process to complete. The process can take approximately five minutes.

  7. Once the provisioning of your Azure resources is done, a URL to the running web application is included in the output.

    Deploying services (azd deploy)
    
      (✓) Done: Deploying service web
    - Endpoint: <https://[container-app-sub-domain].azurecontainerapps.io>
    
    SUCCESS: Your application was provisioned and deployed to Azure in 5 minutes 0 seconds.
    
  8. Use the URL in the console to navigate to your web application in the browser.

    Screenshot of the running URL shortener web application.

  9. In the browser address bar, test the shorten endpoint by adding a URL path such as /shorten?url=https://www.microsoft.com. The page should reload and provide a new URL with a shortened path at the end. Copy the new URL to your clipboard.

    {
      "original": "https://www.microsoft.com",
      "shortened": "http://<container-app-name>.<deployment-name>.<region>.azurecontainerapps.io:<port>/go/<generated-id>"
    }
    
  10. Paste the shortened URL into the address bar and press enter. The page should reload and redirect you to the URL you specified.

Deploy extra services

The original deployment only deployed the minimal services necessary to host the URL shortener app. To use an Azure data service for grain persistence, you must first configure the template to deploy your preferred service.

  1. Using the terminal, run azd env set to configure the DEPLOY_AZURE_TABLE_STORAGE environment variable to enable deployment of Azure Cosmos DB for NoSQL.

    azd env set DEPLOY_AZURE_TABLE_STORAGE true
    
  1. Using the terminal, run azd env set to configure the DEPLOY_AZURE_COSMOS_DB_NOSQL environment variable to enable deployment of Azure Cosmos DB for NoSQL.

    azd env set DEPLOY_AZURE_COSMOS_DB_NOSQL true
    
  1. Run azd provision to redeploy your application architecture with the new configuration. Wait for the provisioning process to complete. The process can take approximately two minutes.

    azd provision
    

    Tip

    Alternatively, you can run azd up again which will both provision your architecture and redeploy your application.

Install NuGet packages

Prior to using the grain, you must install the corresponding Microsoft.Orleans.Clustering.* and Microsoft.Orleans.Persistence.* NuGet packages. These services are using role-based access control for passwordless authentication, so you must also import the Azure.Identity NuGet package.

  1. Change your current working directory to ./src/web/.

    cd ./src/web
    
  2. Import the Azure.Identity package from NuGet using dotnet add package.

    dotnet add package Azure.Identity --version 1.*
    
  3. Import the Microsoft.Orleans.Clustering.AzureStorage and Microsoft.Orleans.Persistence.AzureStorage packages.

    NuGet package
    Clustering Microsoft.Orleans.Clustering.AzureStorage
    Persistence Microsoft.Orleans.Persistence.AzureStorage
    dotnet add package Microsoft.Orleans.Clustering.AzureStorage --version 8.*
    dotnet add package Microsoft.Orleans.Persistence.AzureStorage --version 8.*
    
  1. Import the Azure.Identity package from NuGet using dotnet add package.

    dotnet add package Azure.Identity --version 1.*
    
  2. Import the Microsoft.Orleans.Clustering.Cosmos and Microsoft.Orleans.Persistence.Cosmos packages.

    NuGet package
    Clustering Microsoft.Orleans.Clustering.Cosmos
    Persistence Microsoft.Orleans.Persistence.Cosmos
    dotnet add package Microsoft.Orleans.Clustering.Cosmos --version 8.*
    dotnet add package Microsoft.Orleans.Persistence.Cosmos --version 8.*
    

Configure and redeploy the sample app

The sample app is currently configured to create a localhost cluster and persist grains in-memory. When hosted in Azure, Orleans can be configured to use more scalable, centralized state using a data service in Azure.

  1. Add the following using directives:

    using Azure.Identity;
    using Orleans.Configuration;
    
  2. Find and remove the current builder configuration code in the src/web/Program.cs file.

    builder.Host.UseOrleans(static siloBuilder =>
    {
        siloBuilder
            .UseLocalhostClustering()
            .AddMemoryGrainStorage("urls");
    });
    
  1. Replace the builder configuration with the example here, which implements these key concepts:

    • A conditional environment check is added to ensure the app runs properly in both local development and Azure hosted scenarios.
    • The UseAzureStorageClustering method configures the Orleans cluster to use Azure Table Storage and authenticates using the DefaultAzureCredential class.
    • Use the Configure method to assign IDs for the Orleans cluster.
      • The ClusterID is a unique ID for the cluster that allows clients and silos to talk to one another.
      • The ClusterID can change across deployments.
      • The ServiceID is a unique ID for the application that is used internally by Orleans and should remain consistent across deployments.
    if (builder.Environment.IsDevelopment())
    {
        builder.Host.UseOrleans(static siloBuilder =>
        {
            siloBuilder
                .UseLocalhostClustering()
                .AddMemoryGrainStorage("urls");
        });
    }
    else
    {
        builder.Host.UseOrleans(siloBuilder =>
        {
            var endpoint = new Uri(builder.Configuration["AZURE_TABLE_STORAGE_ENDPOINT"]!);
            var credential = new DefaultAzureCredential();
    
            siloBuilder
                .UseAzureStorageClustering(options =>
                {
                    options.ConfigureTableServiceClient(endpoint, credential);
                })
                .AddAzureTableGrainStorage(name: "urls", options =>
                {
                    options.ConfigureTableServiceClient(endpoint, credential);
                })
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = "url-shortener";
                    options.ServiceId = "urls";
                });
        });
    }
    
  1. Replace the builder configuration with the example here, which implements these key concepts:

    • A conditional environment check is added to ensure the app runs properly in both local development and Azure hosted scenarios.
    • The UseCosmosClustering method configures the Orleans cluster to use Azure Cosmos DB for NoSQL and authenticates using the DefaultAzureCredential class.
    • Use the Configure method to assign IDs for the Orleans cluster.
      • The ClusterID is a unique ID for the cluster that allows clients and silos to talk to one another.
      • The ClusterID can change across deployments.
      • The ServiceID is a unique ID for the application that is used internally by Orleans and should remain consistent across deployments.
    if (builder.Environment.IsDevelopment())
    {
        builder.Host.UseOrleans(static siloBuilder =>
        {
            siloBuilder
                .UseLocalhostClustering()
                .AddMemoryGrainStorage("urls");
        });
    }
    else
    {
        builder.Host.UseOrleans(siloBuilder =>
        {
            var endpoint = builder.Configuration["AZURE_COSMOS_DB_NOSQL_ENDPOINT"]!;
            var credential = new DefaultAzureCredential();
    
            siloBuilder
                .UseCosmosClustering(options =>
                {
                    options.ConfigureCosmosClient(endpoint, credential);
                })
                .AddCosmosGrainStorage(name: "urls", options =>
                {
                    options.ConfigureCosmosClient(endpoint, credential);
                })
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = "url-shortener";
                    options.ServiceId = "urls";
                });
        });
    }
    
  1. Run azd deploy to redeploy your application code as a Docker container. Wait for the deployment process to complete. The process can take approximately one minute.

    azd deploy
    

    Tip

    Alternatively, you can run azd up again which will both provision your architecture and redeploy your application.

Verify the app's behavior

Validate that your updated code works by using the deployed application again and checking to see where it stores data.

  1. In the browser address bar, test the shorten endpoint again by adding a URL path such as /shorten?url=https://learn.microsoft.com/dotnet/orleans. The page should reload and provide a new URL with a shortened path at the end. Copy the new URL to your clipboard.

    {
      "original": "https://learn.microsoft.com/dotnet/orleans",
      "shortened": "http://<container-app-name>.<deployment-name>.<region>.azurecontainerapps.io:<port>/go/<generated-id>"
    }
    
  2. Paste the shortened URL into the address bar and press enter. The page should reload and redirect you to the URL you specified.

Optionally, you can verify that the cluster and state data is stored as expected in the storage account you created.

  1. In the Azure portal, navigate to the resource group that was deployed in this quickstart.

    Important

    The environment name specified earlier in this quickstart is also the target resource group name.

  1. Navigate to the overview page of the Azure Storage account.

  2. Within the navigation, select Storage browser.

  3. Expand the Tables navigation item to discover two tables created by Orleans:

    • OrleansGrainState: This table stores the persistent state grain data used by the application to handle the URL redirects.

    • OrleansSiloInstances: This table tracks essential silo data for the Orleans cluster.

  4. Select the OrleansGrainState table. The table holds a row entry for every URL redirect persisted by the app during your testing.

    A screenshot showing Orleans data in Azure Table Storage.

  1. Navigate to the overview page of the Azure Cosmos DB for NoSQL account.

  2. Within the navigation,select Data Explorer.

  3. Observe the following containers you created earlier in this guide:

    • OrleansStorage: This table stores the persistent state grain data used by the application to handle the URL redirects.

    • OrleansCluster: This table tracks essential silo data for the Orleans cluster.

Scale the app

Orleans is designed for distributed applications. Even an app as simple as the URL shortener can benefit from the scalability of Orleans. You can scale and test your app across multiple instances using the following steps:

  1. Navigate back to the resource group that was deployed in this quickstart.

  2. Navigate to the overview page of the Azure Container Apps app.

  3. Within the navigation, select Scale.

  4. Select Edit and deploy, and then switch to the Scale tab.

  5. Use the slider control to set the min and max replica values to 4. This value ensures the app is running on multiple instances.

  6. Select Create to deploy the new revision.

    A screenshot showing how to scale the Azure Container Apps app.

  7. After the deployment is finished, repeat the testing steps from the previous section. The app continues to work as expected across several instances and can now handle a higher number of requests.

Next step