From d09c4526dbfa9eaeadc0b29e3435a2be2825a354 Mon Sep 17 00:00:00 2001 From: amdeel <52223332+amdeel@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:13:43 -0800 Subject: [PATCH 1/2] Added AppServiceHostingUtility and updated storage settings --- .../AppServicesHostingUtility.cs | 99 +++++++++++++++++++ .../AzureStorageDurabilityProviderFactory.cs | 1 + 2 files changed, 100 insertions(+) create mode 100644 src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs diff --git a/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs b/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs new file mode 100644 index 000000000..d1d2c1e5b --- /dev/null +++ b/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs @@ -0,0 +1,99 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Azure.WebJobs.Extensions.DurableTask +{ + // Taken from Microsoft.Azure.WebJobs.Host https://github.com/Azure/azure-webjobs-sdk/commit/7442bed629d15b4837cd8d18c302381b34f3ddac + internal static class AppServicesHostingUtility + { + private const int BytesPerGB = 1024 * 1024 * 1024; + + public static long GetMemoryLimitBytes(string sku = null, int? numCores = null) + { + sku ??= GetWebsiteSku(); + numCores ??= GetEffectiveCoresCount(); + + if (!string.IsNullOrEmpty(sku)) + { + float memoryGBPerCore = GetMemoryGBPerCore(sku); + + if (memoryGBPerCore > 0) + { + double memoryLimitBytes = memoryGBPerCore * numCores.Value * BytesPerGB; + + if (string.Equals(sku, "IsolatedV2", StringComparison.OrdinalIgnoreCase) && numCores == 8) + { + // special case for upper tier IsolatedV2 where GB per Core + // isn't cleanly linear + memoryLimitBytes = (float)23 * BytesPerGB; + } + + return (long)memoryLimitBytes; + } + } + + // unable to determine memory limit + return -1; + } + + private static int GetEffectiveCoresCount() + { + // When not running on VMSS, the dynamic plan has some limits that mean that a given instance is using effectively a single core, + // so we should not use Environment.Processor count in this case. + var effectiveCores = (IsConsumptionSku() && !IsVMSS()) ? 1 : Environment.ProcessorCount; + return effectiveCores; + } + + private static string GetWebsiteSku() + { + return Environment.GetEnvironmentVariable("WEBSITE_SKU"); + } + + private static bool IsConsumptionSku() + { + string value = GetWebsiteSku(); + return string.Equals(value, "Dynamic", StringComparison.OrdinalIgnoreCase); + } + + private static bool IsVMSS() + { + string value = Environment.GetEnvironmentVariable("RoleInstanceId"); + return value != null && value.IndexOf("HostRole", StringComparison.OrdinalIgnoreCase) >= 0; + } + + internal static float GetMemoryGBPerCore(string sku) + { + if (string.IsNullOrEmpty(sku)) + { + return -1; + } + + // These memory allowances are based on published limits: + // Dynamic SKU: https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale#service-limits + // Premium SKU: https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal#available-instance-skus + // Dedicated SKUs: https://azure.microsoft.com/en-us/pricing/details/app-service/windows/ + switch (sku.ToLower()) + { + case "free": + case "shared": + return 1; + case "dynamic": + return 1.5F; + case "basic": + case "standard": + return 1.75F; + case "premiumv2": + case "isolated": + case "elasticpremium": + return 3.5F; + case "premiumv3": + case "isolatedv2": + return 4; + default: + return -1; + } + } + } +} diff --git a/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs b/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs index 44c286bf4..f63281f25 100644 --- a/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs +++ b/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs @@ -201,6 +201,7 @@ internal AzureStorageOrchestrationServiceSettings GetAzureStorageOrchestrationSe AppName = EndToEndTraceHelper.LocalAppName, LoggerFactory = this.loggerFactory, UseLegacyPartitionManagement = this.azureStorageOptions.UseLegacyPartitionManagement, + MemoryLimitBytes = AppServicesHostingUtility.GetMemoryLimitBytes(), }; if (this.inConsumption) From 1afd46549f314ae0e2b603f6c6db83daac591a55 Mon Sep 17 00:00:00 2001 From: amdeel <52223332+amdeel@users.noreply.github.com> Date: Mon, 27 Feb 2023 13:47:51 -0800 Subject: [PATCH 2/2] updated settings --- .../AppServicesHostingUtility.cs | 12 +++--------- .../AzureStorageDurabilityProviderFactory.cs | 3 ++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs b/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs index d1d2c1e5b..dcb3d3ed1 100644 --- a/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs +++ b/src/WebJobs.Extensions.DurableTask/AppServicesHostingUtility.cs @@ -27,7 +27,7 @@ public static long GetMemoryLimitBytes(string sku = null, int? numCores = null) { // special case for upper tier IsolatedV2 where GB per Core // isn't cleanly linear - memoryLimitBytes = (float)23 * BytesPerGB; + memoryLimitBytes = 23F * BytesPerGB; } return (long)memoryLimitBytes; @@ -40,9 +40,9 @@ public static long GetMemoryLimitBytes(string sku = null, int? numCores = null) private static int GetEffectiveCoresCount() { - // When not running on VMSS, the dynamic plan has some limits that mean that a given instance is using effectively a single core, + // The dynamic plan has some limits that mean that a given instance is using effectively a single core, // so we should not use Environment.Processor count in this case. - var effectiveCores = (IsConsumptionSku() && !IsVMSS()) ? 1 : Environment.ProcessorCount; + var effectiveCores = IsConsumptionSku() ? 1 : Environment.ProcessorCount; return effectiveCores; } @@ -57,12 +57,6 @@ private static bool IsConsumptionSku() return string.Equals(value, "Dynamic", StringComparison.OrdinalIgnoreCase); } - private static bool IsVMSS() - { - string value = Environment.GetEnvironmentVariable("RoleInstanceId"); - return value != null && value.IndexOf("HostRole", StringComparison.OrdinalIgnoreCase) >= 0; - } - internal static float GetMemoryGBPerCore(string sku) { if (string.IsNullOrEmpty(sku)) diff --git a/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs b/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs index f63281f25..9a95ccbd9 100644 --- a/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs +++ b/src/WebJobs.Extensions.DurableTask/AzureStorageDurabilityProviderFactory.cs @@ -201,7 +201,8 @@ internal AzureStorageOrchestrationServiceSettings GetAzureStorageOrchestrationSe AppName = EndToEndTraceHelper.LocalAppName, LoggerFactory = this.loggerFactory, UseLegacyPartitionManagement = this.azureStorageOptions.UseLegacyPartitionManagement, - MemoryLimitBytes = AppServicesHostingUtility.GetMemoryLimitBytes(), + UseOrchestrationHistoryLoadThrottle = true, + TotalProcessMemoryBytes = AppServicesHostingUtility.GetMemoryLimitBytes(), }; if (this.inConsumption)