Skip to content

Commit 00d293b

Browse files
Add HybridCache usage signal, similar to DC (#59886)
Co-authored-by: Marc Gravell <[email protected]>
1 parent f67beca commit 00d293b

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

src/Caching/StackExchangeRedis/src/RedisCache.cs

+7
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ private static RedisValue[] GetHashFields(bool getData) => getData
5353
private long _firstErrorTimeTicks;
5454
private long _previousErrorTimeTicks;
5555

56+
internal bool HybridCacheActive { get; set; }
57+
5658
// StackExchange.Redis will also be trying to reconnect internally,
5759
// so limit how often we recreate the ConnectionMultiplexer instance
5860
// in an attempt to reconnect
@@ -375,6 +377,11 @@ private void TryAddSuffix(IConnectionMultiplexer connection)
375377
{
376378
connection.AddLibraryNameSuffix("aspnet");
377379
connection.AddLibraryNameSuffix("DC");
380+
381+
if (HybridCacheActive)
382+
{
383+
connection.AddLibraryNameSuffix("HC");
384+
}
378385
}
379386
catch (Exception ex)
380387
{
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
5+
using Microsoft.Extensions.Caching.Hybrid;
6+
using Microsoft.Extensions.DependencyInjection;
47
using Microsoft.Extensions.Logging;
58
using Microsoft.Extensions.Options;
69

710
namespace Microsoft.Extensions.Caching.StackExchangeRedis;
811

912
internal sealed class RedisCacheImpl : RedisCache
1013
{
11-
public RedisCacheImpl(IOptions<RedisCacheOptions> optionsAccessor, ILogger<RedisCache> logger)
14+
public RedisCacheImpl(IOptions<RedisCacheOptions> optionsAccessor, ILogger<RedisCache> logger, IServiceProvider services)
1215
: base(optionsAccessor, logger)
1316
{
17+
HybridCacheActive = IsHybridCacheDefined(services);
1418
}
1519

16-
public RedisCacheImpl(IOptions<RedisCacheOptions> optionsAccessor)
20+
public RedisCacheImpl(IOptions<RedisCacheOptions> optionsAccessor, IServiceProvider services)
1721
: base(optionsAccessor)
1822
{
23+
HybridCacheActive = IsHybridCacheDefined(services);
1924
}
25+
26+
// HybridCache optionally uses IDistributedCache; if we're here, then *we are* the DC
27+
private static bool IsHybridCacheDefined(IServiceProvider services)
28+
=> services.GetService<HybridCache>() is not null;
2029
}

src/Caching/StackExchangeRedis/test/CacheServiceExtensionsTests.cs

+43
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
5+
using System.Collections.Generic;
46
using System.Linq;
7+
using System.Threading;
8+
using System.Threading.Tasks;
59
using Microsoft.Extensions.Caching.Distributed;
10+
using Microsoft.Extensions.Caching.Hybrid;
611
using Microsoft.Extensions.DependencyInjection;
12+
using Microsoft.Extensions.DependencyInjection.Extensions;
713
using Microsoft.Extensions.Logging;
814
using Microsoft.Extensions.Logging.Abstractions;
915
using Moq;
@@ -121,4 +127,41 @@ public void AddStackExchangeRedisCache_UsesLoggerFactoryAlreadyRegisteredWithSer
121127

122128
loggerFactory.Verify();
123129
}
130+
131+
[Theory]
132+
[InlineData(true)]
133+
[InlineData(false)]
134+
public void AddStackExchangeRedisCache_HybridCacheDetected(bool hybridCacheActive)
135+
{
136+
// Arrange
137+
var services = new ServiceCollection();
138+
139+
services.AddLogging();
140+
141+
// Act
142+
services.AddStackExchangeRedisCache(options => { });
143+
if (hybridCacheActive)
144+
{
145+
services.TryAddSingleton<HybridCache>(new DummyHybridCache());
146+
}
147+
148+
using var provider = services.BuildServiceProvider();
149+
var cache = Assert.IsAssignableFrom<RedisCache>(provider.GetRequiredService<IDistributedCache>());
150+
Assert.Equal(hybridCacheActive, cache.HybridCacheActive);
151+
}
152+
153+
sealed class DummyHybridCache : HybridCache
154+
{
155+
public override ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState state, Func<TState, CancellationToken, ValueTask<T>> factory, HybridCacheEntryOptions options = null, IEnumerable<string> tags = null, CancellationToken cancellationToken = default)
156+
=> throw new NotSupportedException();
157+
158+
public override ValueTask RemoveAsync(string key, CancellationToken cancellationToken = default)
159+
=> throw new NotSupportedException();
160+
161+
public override ValueTask RemoveByTagAsync(string tag, CancellationToken cancellationToken = default)
162+
=> throw new NotSupportedException();
163+
164+
public override ValueTask SetAsync<T>(string key, T value, HybridCacheEntryOptions options = null, IEnumerable<string> tags = null, CancellationToken cancellationToken = default)
165+
=> throw new NotSupportedException();
166+
}
124167
}

0 commit comments

Comments
 (0)