59

I am using StackExchange.Redis client with Azure Redis Cache Service. Here is my class,

public class RedisCacheService : ICacheService
{
    private readonly ISettings _settings;
    private readonly IDatabase _cache;

    public RedisCacheService(ISettings settings)
    {
        _settings = settings;
        var connectionMultiplexer = ConnectionMultiplexer.Connect(settings.RedisConnection);
        _cache = connectionMultiplexer.GetDatabase();
    }

    public bool Exists(string key)
    {
        return _cache.KeyExists(key);
    }

    public void Save(string key, string value)
    {
        var ts = TimeSpan.FromMinutes(_settings.CacheTimeout);
        _cache.StringSet(key, value, ts);
    }

    public string Get(string key)
    {
        return _cache.StringGet(key);
    }

    public void Remove(string key)
    {
        // How to remove one
    }

    public void Clear()
    {
        // How to remove all
    }
}

Update: From the help of Marc, Here is my final class

public class RedisCacheService : ICacheService
{
    private readonly ISettings _settings;
    private readonly IDatabase _cache;
    private static ConnectionMultiplexer _connectionMultiplexer;

    static RedisCacheService()
    {
        var connection = ConfigurationManager.AppSettings["RedisConnection"];
        _connectionMultiplexer = ConnectionMultiplexer.Connect(connection);
    }

    public RedisCacheService(ISettings settings)
    {
        _settings = settings;
        _cache = _connectionMultiplexer.GetDatabase();
    }

    public bool Exists(string key)
    {
        return _cache.KeyExists(key);
    }

    public void Save(string key, string value)
    {
        var ts = TimeSpan.FromMinutes(_settings.CacheTimeout);
        _cache.StringSet(key, value, ts);
    }

    public string Get(string key)
    {
        return _cache.StringGet(key);
    }

    public void Remove(string key)
    {
        _cache.KeyDelete(key);
    }

    public void Clear()
    {
        var endpoints = _connectionMultiplexer.GetEndPoints(true);
        foreach (var endpoint in endpoints)
        {
            var server = _connectionMultiplexer.GetServer(endpoint);
            server.FlushAllDatabases();    
        }
    }
}

Now I don't know how to remove all items or single item from redis cache.

Imran Qadir Baksh - Baloch
  • 32,612
  • 68
  • 179
  • 322
  • 8
    As a side note: I would strongly recommend adding in-memory cache in front of redis; redis is fast, but a redis request that **you don't make** is faster – Marc Gravell Jul 02 '14 at 13:28
  • 1
    @MarcGravell, I agree, that's why I have .Net Memory Cache as well. But it is not distributed. Means I need support of multiple servers. – Imran Qadir Baksh - Baloch Jul 02 '14 at 13:32
  • @MarcGravell I specifically have used Redis because I have a scaled out environment with many application servers. In-Memory cache wouldn't work in that case, correct? – Issa Fram Feb 13 '18 at 18:45
  • 1
    @IssaFram sure it can - as long as you have some kind of policy for publishing cache invalidations. Fortunately, redis comes with pub/sub built in, and you can enable keyspace notifications if you *really* want. We use exactly this setup (via opt-in publish on keys that we actively want to be immediately invalidated, not via automated keyspace notifications) to handle a memory+redis cache on a multi-server cluster – Marc Gravell Feb 14 '18 at 09:17

5 Answers5

77

To remove a single item:

_cache.KeyDelete(key);

To remove all involves the FLUSHDB or FLUSHALL redis command; both are available in StackExchange.Redis; but, for reasons discussed here, they are not on the IDatabase API (because: they affect servers, not logical databases).

As per the "So how do I use them?" on that page:

server.FlushDatabase(); // to wipe a single database, 0 by default
server.FlushAllDatabases(); // to wipe all databases

(quite possibly after using GetEndpoints() on the multiplexer)

FabianSilva
  • 405
  • 6
  • 18
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 4
    Thanks. Howdo I get the server. – Imran Qadir Baksh - Baloch Jul 02 '14 at 13:11
  • 1
    @user960567 from the multiplexer; `multiplexer.GetServer(...)`; the easiest thing to do is to request an endpoint from `multiplexer.GetEndpoints(true)`. Obviously this is all a lot easier if you are only talking to one server. This is all explained at the end of the linked article. – Marc Gravell Jul 02 '14 at 13:12
  • But I only have connection string from azure, xx.redis.cache.windows.net,ssl=true,password=.... How then I get the server. – Imran Qadir Baksh - Baloch Jul 02 '14 at 13:14
  • Also my RedisCacheService is per request(asp.net). Is it fine to instantiate ConnectionMultiplexer and IDatabase per request. – Imran Qadir Baksh - Baloch Jul 02 '14 at 13:15
  • @user960567 the `IDatabase`: yes; the `ConnectionMultiplexer`: no; please read the first paragraph of [Basic Usage](https://github.com/StackExchange/StackExchange.Redis/blob/master/Docs/Basics.md) – Marc Gravell Jul 02 '14 at 13:17
  • OK Thanks. GetEndpoints means I have to loop all end points and get server and call FlushAllDatabases. Thanks. – Imran Qadir Baksh - Baloch Jul 02 '14 at 13:19
  • @user960567 you should probably only call `FlushAllDatabases` on the **master** servers (`!IsSlave`); and most likely that actually means one server. – Marc Gravell Jul 02 '14 at 13:21
  • I am using Azure Redis Preview(Basic). Not sure they use Master/Slave. – Imran Qadir Baksh - Baloch Jul 02 '14 at 13:28
  • 1
    @user960567 actually, I'm pretty sure they do, but: I suspect that isn't available to the external caller; so indeed, if you only know one address, there's a very good chance that it is a master, and that `GetEndpoints` will return exactly one item – Marc Gravell Jul 02 '14 at 13:30
  • Mark I got another interesting issue, http://stackoverflow.com/questions/27718453/redis-cache-getting-timeout-with-sync-requests-and-slow-response-with-async-requ – Imran Qadir Baksh - Baloch Dec 31 '14 at 08:46
  • Mark please check I have added bounty now http://stackoverflow.com/questions/27718453/redis-cache-getting-timeout-with-sync-requests-and-slow-response-with-async-requ – Imran Qadir Baksh - Baloch Mar 28 '15 at 18:23
28

I could not able to flush database in Azure Redis Cache, got this error:

This operation is not available unless admin mode is enabled: FLUSHDB

Instead iterate through all keys to delete:

var endpoints = connectionMultiplexer.GetEndPoints();
var server = connectionMultiplexer.GetServer(endpoints.First());
//FlushDatabase didn't work for me: got error admin mode not enabled error
//server.FlushDatabase();
var keys = server.Keys();
foreach (var key in keys)
{
  Console.WriteLine("Removing Key {0} from cache", key.ToString());
  _cache.KeyDelete(key);
}
RaSi
  • 470
  • 5
  • 8
  • 18
    Make sure you set `allowAdmin=true` in the config string (or `ConfigurationOptions`). https://github.com/StackExchange/StackExchange.Redis/blob/master/Docs/Configuration.md#basic-configuration-strings – Sean Kearney Jul 17 '14 at 20:23
  • 1
    @SeanKearney - The link is broken. Here is the updated link https://stackexchange.github.io/StackExchange.Redis/Configuration#configuration-options – Karthik Aug 21 '19 at 05:15
13

Both answers by @Rasi and @Marc Gravell contain pieces of code needed. Based on above, here is working snippet assuming there is just 1 server:

You need to connect to redis with allowAdmin=true, one way to obtain such options is to assign AllowAdmin to already parsed string:

var options = ConfigurationOptions.Parse("server:6379");
options.AllowAdmin = true;
var redis = ConnectionMultiplexer.Connect(options);

Then to flush all databases:

var endpoints = redis.GetEndPoints();
var server = redis.GetServer(endpoints[0]);
server.FlushAllDatabases();

Above will work on any redis deployment, not just Azure.

Tomasz Sętkowski
  • 2,142
  • 1
  • 18
  • 15
1

You can delete hash as well ie if you want to clear specific value from any cached list. For example, we have an emp list and inside with different department as cached.

public static void DeleteHash(string key, string cacheSubKey)
        {
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException("key");

            Cache.HashDelete(key, cacheSubKey);
        }

so you can pass Key name and cache subkey as well.

Rushabh Master
  • 450
  • 4
  • 13
0

To Remove an item from List in Distributed cache use ListRemoveAsync() function supported by Distributed cache library and can be accessed through IDistributedCache interface

 public async Task RemoveListByIndexAsync(string key, string cacheValue)
 {
   RedisValue redisValue = cacheValue // value of item in the list to be removed;
   await _cache.ListRemoveAsync(key, redisValue);
 }
  • key - cacahe key redisValue
  • item - item in the list to be removed.

Note - Make sure that the Redis value which has to be removed should exactly the item of the list in the existing in the cache.

Dev-lop-er
  • 578
  • 1
  • 7
  • 16