StackExchange.Redis 命令扩展

StackExchange.Redis 命令扩展

Intro

在之前的文章中有简单介绍过 StackExchange.Redis 直接调用 Redis 命令来实现调用 Stream 的根据消息 Id 来控制消息长度,因为 StackExchange.Redis 目前还不支持根据消息 Id 控制 Stream 消息长度,目前有很多 6.2 以后带来的新特性大多还不支持。

前段时间,给 StackExchange.Redis 提了一个 PR 支持了一个 Redis 6.2 的新命令 GETDEL,给大家分享一下,有想去蹭贡献的也可以尝试贡献一下

GETDEL

GETDEL 是 Redis 6.2 中引入的新功能中的其中一个,是针对 String 类型的数据的命令,如同命令名称一样,先 GET 并删除某一个 key,返回 key 的内容,如下面示例一样

redis> SET mykey "Hello"

"OK"

redis> GETDEL mykey

"Hello"

redis> GET mykey

(nil)

Implement

命令比较简单,不会造成产生破坏性的变更,实现起来也是比较简单,主要是新增下面两个 API:

RedisValue StringGetDelete(RedisKey key, CommandFlags flags = CommandFlags.None);
Task<RedisValue> StringGetDeleteAsync(RedisKey key, CommandFlags flags = CommandFlags.None);

分别定义在 IDatabase/IDatabaseAsync

对于其实现来说,会增加一个 Redis 命令的枚举定义,需要在 RedisCommand 中增加一个新命令 GETDEL

enum RedisCommand:
+  GETDEL,

实现需要修改的地方有三个:

RedisDatabase,新增的 API 实现如下

public RedisValue StringGetDelete(RedisKey key, CommandFlags flags = CommandFlags.None)
{
    var msg = Message.Create(Database, flags, RedisCommand.GETDEL, key);
    return ExecuteSync(msg, ResultProcessor.RedisValue);
}

public Task<RedisValue> StringGetDeleteAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
{
    var msg = Message.Create(Database, flags, RedisCommand.GETDEL, key);
    return ExecuteAsync(msg, ResultProcessor.RedisValue);
}

DatabaseWrapper:

public RedisValue StringGetDelete(RedisKey key, CommandFlags flags = CommandFlags.None)
{
    return Inner.StringGetDelete(ToInner(key), flags);
}

WrapperBase:

public Task<RedisValue> StringGetDeleteAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
{
    return Inner.StringGetDeleteAsync(ToInner(key), flags);
}

单元测试的变更如下:

tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs:

[Fact]
public void StringGetDelete()
{
    wrapper.StringGetDelete("key", CommandFlags.None);
    mock.Verify(_ => _.StringGetDelete("prefix:key", CommandFlags.None));
}

tests/StackExchange.Redis.Tests/WrapperBaseTests.cs:

[Fact]
public void StringGetDeleteAsync()
{
    wrapper.StringGetDeleteAsync("key", CommandFlags.None);
    mock.Verify(_ => _.StringGetDeleteAsync("prefix:key", CommandFlags.None));
}

tests/StackExchange.Redis.Tests/Strings.cs: 实际使用也可以参数这两个测试用例

[Fact]
public void GetDelete()
{
    using (var muxer = Create())
    {
        Skip.IfMissingFeature(muxer, nameof(RedisFeatures.GetDelete), r => r.GetDelete);

        var conn = muxer.GetDatabase();
        var prefix = Me();
        conn.KeyDelete(prefix + "1", CommandFlags.FireAndForget);
        conn.KeyDelete(prefix + "2", CommandFlags.FireAndForget);
        conn.StringSet(prefix + "1", "abc", flags: CommandFlags.FireAndForget);

        Assert.True(conn.KeyExists(prefix + "1"));
        Assert.False(conn.KeyExists(prefix + "2"));

        var s0 = conn.StringGetDelete(prefix + "1");
        var s2 = conn.StringGetDelete(prefix + "2");

        Assert.False(conn.KeyExists(prefix + "1"));
        Assert.Equal("abc", s0);
        Assert.Equal(RedisValue.Null, s2);
    }
}

[Fact]
public async Task GetDeleteAsync()
{
    using (var muxer = Create())
    {
        Skip.IfMissingFeature(muxer, nameof(RedisFeatures.GetDelete), r => r.GetDelete);

        var conn = muxer.GetDatabase();
        var prefix = Me();
        conn.KeyDelete(prefix + "1", CommandFlags.FireAndForget);
        conn.KeyDelete(prefix + "2", CommandFlags.FireAndForget);
        conn.StringSet(prefix + "1", "abc", flags: CommandFlags.FireAndForget);

        Assert.True(conn.KeyExists(prefix + "1"));
        Assert.False(conn.KeyExists(prefix + "2"));

        var s0 = conn.StringGetDeleteAsync(prefix + "1");
        var s2 = conn.StringGetDeleteAsync(prefix + "2");

        Assert.False(conn.KeyExists(prefix + "1"));
        Assert.Equal("abc", await s0);
        Assert.Equal(RedisValue.Null, await s2);
    }
}

More

主要的变更就是这些了,是不是看起来也简单的,除了上面的基本实现就是要增加一些测试用例以及本地进行一下测试,看是不是可以按预期工作,有一些功能可能会要求集成测试

除了上面还有一个小点,就是如果不是只读命令需要声明命令是 MasterOnly 的,在 src/StackExchange.Redis/Message.cs 中的 public static bool IsMasterOnly(RedisCommand command) 声明即可,除此之外,StackExchange.Redis 会建议增加 ReleaseNote

如果你愿意也可以尝试去贡献一下 https://github.com/StackExchange/StackExchange.Redis/issues

References

  • https://github.com/StackExchange/StackExchange.Redis/pull/1840

  • https://github.com/StackExchange/StackExchange.Redis/issues/1729

  • https://redis.io/commands/getdel

  • https://github.com/StackExchange/StackExchange.Redis/issues

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值