Skip to content

Commit

Permalink
Automatically detect and tune for Azure Managed Redis caches (#2818)
Browse files Browse the repository at this point in the history
Detect when connecting to a new Azure Managed Redis cache, and adjust default connection settings to align with their capabilities. 

More about Azure Managed Redis: https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-overview
  • Loading branch information
philon-msft authored Nov 25, 2024
1 parent 0071148 commit 11ef77d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 38 deletions.
1 change: 1 addition & 0 deletions docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Current package versions:

- Format IPv6 endpoints correctly when rewriting configration strings ([#2813 by mgravell](https://github.com/StackExchange/StackExchange.Redis/pull/2813))
- Update default Redis version from 4.0.0 to 6.0.0 for Azure Redis resources ([#2810 by philon-msft](https://github.com/StackExchange/StackExchange.Redis/pull/2810))
- Detect Azure Managed Redis caches and tune default connection settings for them ([#2818 by philon-msft](https://github.com/StackExchange/StackExchange.Redis/pull/2818))

## 2.8.16

Expand Down
35 changes: 28 additions & 7 deletions src/StackExchange.Redis/Configuration/AzureOptionsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,48 @@ public class AzureOptionsProvider : DefaultOptionsProvider
public override Version DefaultVersion => RedisFeatures.v6_0_0;

/// <summary>
/// List of domains known to be Azure Redis, so we can light up some helpful functionality
/// Lists of domains known to be Azure Redis, so we can light up some helpful functionality
/// for minimizing downtime during maintenance events and such.
/// </summary>
private static readonly string[] azureRedisDomains = new[]
{
".redis.cache.windows.net",
".redis.cache.chinacloudapi.cn",
".redis.cache.usgovcloudapi.net",
".redis.cache.cloudapi.de",
".redisenterprise.cache.azure.net",
};

private static readonly string[] azureManagedRedisDomains = new[]
{
".redis.azure.net",
".redis.chinacloudapi.cn",
".redis.usgovcloudapi.net",
};

/// <inheritdoc/>
public override bool IsMatch(EndPoint endpoint)
{
if (endpoint is DnsEndPoint dnsEp)
{
foreach (var host in azureRedisDomains)
if (IsHostInDomains(dnsEp.Host, azureRedisDomains) || IsHostInDomains(dnsEp.Host, azureManagedRedisDomains))
{
if (dnsEp.Host.EndsWith(host, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
return true;
}
}

return false;
}

private bool IsHostInDomains(string hostName, string[] domains)
{
foreach (var domain in domains)
{
if (hostName.EndsWith(domain, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}

return false;
}

Expand All @@ -65,6 +82,10 @@ public override bool GetDefaultSsl(EndPointCollection endPoints)
{
return true;
}
if (dns.Port == 10000 && IsHostInDomains(dns.Host, azureManagedRedisDomains))
{
return true; // SSL is enabled by default on AMR caches
}
break;
case IPEndPoint ip:
if (ip.Port == 6380)
Expand Down
46 changes: 15 additions & 31 deletions tests/StackExchange.Redis.Tests/ConfigTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Pipelines;
Expand All @@ -25,7 +26,6 @@ public class ConfigTests : TestBase
public ConfigTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { }

public Version DefaultVersion = new(3, 0, 0);
public Version DefaultAzureVersion = new(6, 0, 0);

[Fact]
public void ExpectedFields()
Expand Down Expand Up @@ -132,12 +132,21 @@ public void SslProtocols_InvalidValue()
Assert.Throws<ArgumentOutOfRangeException>(() => ConfigurationOptions.Parse("myhost,sslProtocols=InvalidSslProtocol"));
}

[Fact]
public void ConfigurationOptionsDefaultForAzure()
{
var options = ConfigurationOptions.Parse("contoso.redis.cache.windows.net");
Assert.True(options.DefaultVersion.Equals(DefaultAzureVersion));
[Theory]
[InlineData("contoso.redis.cache.windows.net:6380", true)]
[InlineData("contoso.REDIS.CACHE.chinacloudapi.cn:6380", true)] // added a few upper case chars to validate comparison
[InlineData("contoso.redis.cache.usgovcloudapi.net:6380", true)]
[InlineData("contoso.redisenterprise.cache.azure.net:10000", false)]
[InlineData("contoso.redis.azure.net:10000", true)]
[InlineData("contoso.redis.chinacloudapi.cn:10000", true)]
[InlineData("contoso.redis.usgovcloudapi.net:10000", true)]
public void ConfigurationOptionsDefaultForAzure(string hostAndPort, bool sslShouldBeEnabled)
{
Version defaultAzureVersion = new(6, 0, 0);
var options = ConfigurationOptions.Parse(hostAndPort);
Assert.True(options.DefaultVersion.Equals(defaultAzureVersion));
Assert.False(options.AbortOnConnectFail);
Assert.Equal(sslShouldBeEnabled, options.Ssl);
}

[Fact]
Expand All @@ -148,31 +157,6 @@ public void ConfigurationOptionsForAzureWhenSpecified()
Assert.True(options.AbortOnConnectFail);
}

[Fact]
public void ConfigurationOptionsDefaultForAzureChina()
{
// added a few upper case chars to validate comparison
var options = ConfigurationOptions.Parse("contoso.REDIS.CACHE.chinacloudapi.cn");
Assert.True(options.DefaultVersion.Equals(DefaultAzureVersion));
Assert.False(options.AbortOnConnectFail);
}

[Fact]
public void ConfigurationOptionsDefaultForAzureGermany()
{
var options = ConfigurationOptions.Parse("contoso.redis.cache.cloudapi.de");
Assert.True(options.DefaultVersion.Equals(DefaultAzureVersion));
Assert.False(options.AbortOnConnectFail);
}

[Fact]
public void ConfigurationOptionsDefaultForAzureUSGov()
{
var options = ConfigurationOptions.Parse("contoso.redis.cache.usgovcloudapi.net");
Assert.True(options.DefaultVersion.Equals(DefaultAzureVersion));
Assert.False(options.AbortOnConnectFail);
}

[Fact]
public void ConfigurationOptionsDefaultForNonAzure()
{
Expand Down
16 changes: 16 additions & 0 deletions tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Threading;
Expand Down Expand Up @@ -65,6 +66,21 @@ public void IsMatchOnDomain()
Assert.IsType<DefaultOptionsProvider>(provider);
}

[Theory]
[InlineData("contoso.redis.cache.windows.net")]
[InlineData("contoso.REDIS.CACHE.chinacloudapi.cn")] // added a few upper case chars to validate comparison
[InlineData("contoso.redis.cache.usgovcloudapi.net")]
[InlineData("contoso.redisenterprise.cache.azure.net")]
[InlineData("contoso.redis.azure.net")]
[InlineData("contoso.redis.chinacloudapi.cn")]
[InlineData("contoso.redis.usgovcloudapi.net")]
public void IsMatchOnAzureDomain(string hostName)
{
var epc = new EndPointCollection(new List<EndPoint>() { new DnsEndPoint(hostName, 0) });
var provider = DefaultOptionsProvider.GetProvider(epc);
Assert.IsType<AzureOptionsProvider>(provider);
}

[Fact]
public void AllOverridesFromDefaultsProp()
{
Expand Down

0 comments on commit 11ef77d

Please sign in to comment.