Hi,

Recently, I'm reading codes about Modules, it is a big change of 4.0, there are so many APIs that we can do lots of extensions with Modules.

When I read the API RM_Call() with "!" flag and RM_Replicate(), I remember redis.call() and redis.replicate_commands() in Lua scripting, also wrapped into the MULTI/EXEC.

Then I read samples in modules directory:

modules/helloworld.c

int HelloRepl1_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
    REDISMODULE_NOT_USED(argv);
    REDISMODULE_NOT_USED(argc);
    RedisModule_AutoMemory(ctx);
    RedisModule_Replicate(ctx,"ECHO","c","foo");

    /* Using the "!" modifier we replicate the command if it
     * modified the dataset in some way. */
    RedisModule_Call(ctx,"INCR","c!","foo");
    RedisModule_Call(ctx,"INCR","c!","bar");

    RedisModule_ReplyWithLongLong(ctx,0);

    return REDISMODULE_OK;
}

It works well, but when I try to call them in MULTI/EXEC, something strange happened:

$redis-cli
127.0.0.1:6379> module load modules/helloworld.so
OK
127.0.0.1:6379> hello.repl1
(integer) 0
127.0.0.1:6379> multi
OK
127.0.0.1:6379> hello.repl1
QUEUED
127.0.0.1:6379> exec
1) (integer) 0

$cat appendonly.aof
*1
$5
MULTI
*1
$5
MULTI
*2
$4
INCR
$3
foo
*2
$4
INCR
$3
bar
*2
$4
ECHO
$3
foo
*1
$4
EXEC
*1
$4
exec

There are nested MULTI contexts..., also happened when we execute a Lua script with redis.replicate_commands() in MULTI/EXEC.

To make matters worse, if we queue other write commands in MULTI/EXEC with replicate things, that will break atomicity of transaction, because EXEC has already been generated by redis.replicate_commands() or RM_Replicate() before the real EXEC we want!

I just did a little change, see #4340 .

Another question, commands in RedisModule_Replicate() are not executed by the caller, just replicate to slaves and aof file, is that designed purposely or a bug?