You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Redis C模块覆盖内置SET命令的技术实现问题咨询

解决Redis SET命令扩展:同步发布值到指定频道

针对你遇到的问题——想要让Redis的SET操作自动把值发布到指定频道,而默认的键空间事件又不包含值,直接覆盖内置SET命令失败,rename-command的尝试没达到预期,我整理了两种可行的解决方案:

方法一:使用命令钩子拦截SET执行

Redis模块API提供了命令钩子(Command Hooks)功能,可以在命令执行前后插入自定义逻辑,不需要修改原命令名,对客户端完全透明。

实现步骤:

  1. 在模块初始化时注册SET命令的钩子,指定要监听的命令为SET。
  2. 在钩子函数中,当命令执行成功后,提取SET操作的值,调用RedisModule_Publish发布到目标频道。

代码示例片段:

#include "redismodule.h"

// 命令执行后的钩子函数
int PostSetHook(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, long long reply) {
    // 确认是SET命令且执行成功
    if (reply == REDISMODULE_OK && argc >= 3) {
        RedisModuleString *channel = RedisModule_CreateString(ctx, "set_notifications", strlen("set_notifications"));
        RedisModuleString *value = argv[2]; // SET命令的第三个参数是值
        RedisModule_Publish(ctx, channel, value);
        RedisModule_FreeString(ctx, channel);
    }
    return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "setpub", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    // 注册SET命令的后置钩子
    if (RedisModule_AddCommandHook(ctx, "SET", NULL, PostSetHook, REDISMODULE_HOOK_POST) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    return REDISMODULE_OK;
}

注意事项:

  • 钩子会拦截所有SET命令的执行,包括带EX、PX、NX等参数的变体,不需要额外处理参数兼容问题。
  • 确保模块加载后,钩子生效,你可以通过执行SET key value后,用SUBSCRIBE set_notifications验证是否收到值。

方法二:重命名内置命令+自定义实现SET

如果钩子方案不满足你的需求,你可以通过重命名内置SET命令,然后自己实现一个兼容原SET功能的自定义命令,同时添加发布逻辑。

实现步骤:

  1. 在Redis配置文件中添加rename-command SET SET_OLD,把原SET命令重命名为SET_OLD。
  2. 在自定义模块中创建新的SET命令,内部先调用原SET_OLD命令完成存储,再发布值到频道。

代码示例片段:

#include "redismodule.h"

int SetPubCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    // 调用原SET命令(已重命名为SET_OLD)
    RedisModuleCallReply *reply = RedisModule_Call(ctx, "SET_OLD", "v", argv+1, argc-1);
    if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_ERROR) {
        RedisModule_ReplyWithCallReply(ctx, reply);
        RedisModule_FreeCallReply(reply);
        return REDISMODULE_OK;
    }

    // 发布值到指定频道
    if (argc >=3) {
        RedisModuleString *channel = RedisModule_CreateString(ctx, "set_notifications", strlen("set_notifications"));
        RedisModuleString *value = argv[2];
        RedisModule_Publish(ctx, channel, value);
        RedisModule_FreeString(ctx, channel);
    }

    RedisModule_ReplyWithCallReply(ctx, reply);
    RedisModule_FreeCallReply(reply);
    return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "setpub", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    // 创建自定义SET命令
    if (RedisModule_CreateCommand(ctx, "SET", SetPubCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    return REDISMODULE_OK;
}

关键注意点:

  • 自定义SET命令的参数规则("write deny-oom", 1, 1, 1")要和原SET保持一致,确保客户端调用无差异。
  • 必须先在配置中重命名原SET,再加载模块创建新的SET命令,否则Redis会报错提示命令已存在。

为什么你之前的尝试没成功?

  • RedisModule_CreateCommand无法覆盖内置命令:这是Redis的保护机制,防止模块意外破坏核心命令的行为,所以直接创建同名命令会失败。
  • rename-command + setpub的问题:如果你的setpub命令没有完整兼容原SET的所有参数(比如过期、存在性判断等),会导致功能缺失;另外顺序很重要,必须先重命名原SET,再创建自定义命令。

内容的提问来源于stack exchange,提问作者Danny Willems

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:16:34