-
Notifications
You must be signed in to change notification settings - Fork 10.3k
[RedisCache] Allow injection of ConnectionMultiplexer #28379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Just noticed there is an open pull request enabling this scenario. But did not find an issue discussing the proposed change, so I'll keep this one open for discussion. |
Closing aspnet/Caching#318 as it entails to a breaking change. Keeping this bug open for any alternatives or for a potential major release change. |
I believe that injecting IConnectionMultiplexer as a dependency is the path to go. I share @epignosisx concerns about StackExchange.Redis being a implementation detail or not. |
@muratg could you share where does the team stand on whether StackExchange.Redis should be kept as an implementation detail or not? Answering this question is critical to make progress on this issue. As @israellot pointed out the alternatives are more abstractions that probably will be undesirable. |
cc @davidfowl |
Yes we should allow for this. Not sure about injecting the |
I know the application has created a |
Tentatively putting this in 2.2.0. We'll need to identify what the best way to achieve this is. |
FYI this issue is referenced here: |
@muratg Any update to this? |
Over a year old and nothing new ? |
This is not currently in scope. We'll revisit in a future release. |
+1 |
@effyteva That would become a problem if other libraries did the same thing - everyone would create their own multiplexer and expect others to use theirs. |
For Data Protection we can use |
I also encountered the same problem, for some redis data, I need to use IConnectionMultiplexer |
@muratg Any update to this? |
I'm no longer working with the ASP.NET team, so paging @anurse. @DamianEdwards and @davidfowl here. |
We don't have plans to do this for 3.0, but it is on our backlog to consider for a future version. |
Hi, it seems this feature won't be available anytime soon. Is there a workaround for this? I need to use the redis cache both via IDistributedCache and with native redis commands. Thanks! |
@bragma I don't disagree at all that it would be a good plan for us to allow injecting it, but can you provide more context on why you require that your native redis commands and the redis cache use the same instance of the |
@anurse I think that's why there's
|
@bragma the workaround I have ended up using is getting a hold of the public static class RedisCacheExtensions
{
/// <summary>
/// The ASP.NET Core's RedisCache does not expose the ConnectionMultiplexer required for more advanced Redis scenarios
/// and it is recommended to have just one ConnectionMultiplexer.
/// We are left with no option but to use reflection to get a hold of the connection.
/// </summary>
public static async Task<ConnectionMultiplexer> GetConnectionAsync(this RedisCache cache, CancellationToken cancellationToken = default)
{
//ensure connection is established
await((Task)typeof(RedisCache).InvokeMember("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, cache, new object[] { cancellationToken }));
//get connection multiplexer
var fi = typeof(RedisCache).GetField("_connection", BindingFlags.Instance | BindingFlags.NonPublic);
var connection = (ConnectionMultiplexer)fi.GetValue(cache);
return connection;
}
} Usage: public class RedisHealthCheck : IHealthCheck
{
private readonly RedisCache _cache;
public RedisHealthCheck(IDistributedCache cache)
{
_cache = (RedisCache)cache;
}
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
var connection = await _cache.GetConnectionAsync(cancellationToken);
await connection.GetDatabase()
.PingAsync();
return HealthCheckResult.Healthy();
}
catch (Exception ex)
{
return new HealthCheckResult(context.Registration.FailureStatus, exception: ex);
}
}
} |
Yep, I understand the purpose. Just trying to understand what issues you're seeing with using two separate instances to help prioritize. Is there extra load in your system? (memory usage, cpu, etc.) We'll definitely be investigating this, but I just want to understand how this issue is negatively impacting applications right now in order to help us prioritize. |
Well, the context is more or less the same as others requesting for it. I need to stuff some data in the cache preserving compatibility with other services reading it via IDistributedCache and also use all other nice Redis data types for other purposes. Of course I could just ditch the IDistributedCache implementation and use only the Redis package replicating the data format, but any change in the implementation of distributed cache for redis would require me to change my code.
Thanks a lot! |
This isn't necessarily wrong, but it would probably be best to have actual data to know the impact of that. I don't have a specific workaround for you unfortunately. The main issue here is that the cache doesn't give you a way to specify the multiplexer, which isn't easy to work around. Honestly, I would investigate the impact of two separate |
I was wondering an idea, which may be totally naive and stupid, so I am exposing it for comments. Suppose RedisCache is changed by adding something like:
And an interface like this is added:
This would allow to create RedisCache as a singleton for a IDistributedRedisCache and IDistributedCache would still work, I suppose. It seems like a minor change to me. I am missing anything? Thanks a lot! |
I like the idea of
|
@napalm684 I've updated the original issue with an API proposal. We'll review the API, you can prepare a PR in the meantime or wait for final approval. |
@davidfowl I guess I'm a little confused what the factory provides when the property is already private on that class if I recall correctly. Is there an example of this I could reference? |
The options could have a |
Putting the burden on the application to create and pass a connection multiplexer in the options would add un-needed complexity. Now the client has to know how to create this type properly and connect, which can be error prone if not done right. Being able to inject |
They can inject the multiplexer trivially if that's what they want to do and apply it to the options. We generally don't like assuming the services that are in the container should be automagically consumed by components, especially when they are optional. The API above is the standard pattern introduced in all extensions and ASP.NET Core APIs for configurability. |
Is there a process to take this? I would like to make a PR if someone hasn't already. |
We're gonna discuss the API next week and then you can send the PR |
Awesome will you post the result of the discussion here and then I can submit? |
So I took a stab in this PR #31879 . I would like some feedback (whether I did this properly - first timer here) and am willing to assist in whatever way necessary to apply feedback. |
We would benefit from this fix. Can someone review PR #31879? |
@davidfowl any word on the api design discussion? If things didn't change my PR is still out there. Otherwise let's talk about updates/feedback? Thanks! |
Additional API feedback provided in the PR |
I commented in the PR @pranavkm let's talk about a few things please. |
With the merge of PR #32266 can this be closed? |
Yup, thanks for the contribution @napalm684 ! |
I've registered servoces.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect("redis:6379"));
builder.AddRedisQueryStorage(x => x.GetApplicationServices().GetRequiredService<IConnectionMultiplexer>().GetDatabase());
builder.AddRedisSubscriptions(x => x.GetRequiredService<IConnectionMultiplexer>()); I've also raised an issue in Xabril health checks to do something similar in Xabaril/AspNetCore.Diagnostics.HealthChecks#750: services
.AddHealthChecks()
.AddRedis(sp => sp.GetRequiredService<IConnectionMultiplexer>()); Can this be a supported scenario for the |
Currently the
RedisCache
creates theConnectionMultiplexer
and does not allow access to it. This prevents the application from reusing theConnectionMultiplexer
for other operations like PubSub.Granted, the application could create another
ConnectionMultiplexer
, but the recommendation is to have only one per application.I was thinking if it would be possible to have a separate constructor for
RedisCache
that would receive theConnectionMultiplexer
. I understand that so far Microsoft.Extensions.Caching.Redis did not leak any implementation details about its usage of StackExchange.Redis. However, I noticed that Microsoft.AspNetCore.DataProtection.Redis leaks StackExchange.Redis types here. So, I'm unclear about how you feel about keeping StackExchange.Redis as an implementation detail.Proposed API
namespace Microsoft.Extensions.Caching.StackExchangeRedis { public class RedisCacheOptions { + Func<IConnectionMultiplexer> ConnectionMultiplexerFactory { get; set; } }
The text was updated successfully, but these errors were encountered: