diff --git a/src/server.c b/src/server.c index f343ff1bba..3aaddd38d8 100644 --- a/src/server.c +++ b/src/server.c @@ -3943,6 +3943,13 @@ int processCommand(client *c) { * and then resume the execution. */ blockPostponeClient(c); } else { + if (c->cmd->proc == execCommand) { + discardTransaction(c); + } else { + flagTransaction(c); + } + c->duration = 0; + c->cmd->rejected_calls++; addReplyErrorSds(c, sdscatprintf(sdsempty(), "-REDIRECT %s:%d", server.primary_host, server.primary_port)); } return C_OK; diff --git a/tests/integration/replica-redirect.tcl b/tests/integration/replica-redirect.tcl index b62ce4ca3b..b4e5a74b66 100644 --- a/tests/integration/replica-redirect.tcl +++ b/tests/integration/replica-redirect.tcl @@ -9,8 +9,28 @@ start_server {tags {needs:repl external:skip}} { set replica_port [srv 0 port] set replica_pid [srv 0 pid] - r replicaof $primary_host $primary_port - wait_replica_online $primary + test {write command inside MULTI is QUEUED, EXEC should be REDIRECT} { + set rr [valkey_client] + $rr client capa redirect + $rr multi + assert_equal "QUEUED" [$rr set foo bar] + + # Change the current instance to be a replica + r replicaof $primary_host $primary_port + wait_replica_online $primary + + assert_error "REDIRECT*" {$rr exec} + $rr close + } + + test {write command inside MULTI is REDIRECT, EXEC should be EXECABORT} { + set rr [valkey_client] + $rr client capa redirect + $rr multi + assert_error "REDIRECT*" {$rr set foo bar} + assert_error "EXECABORT*" {$rr exec} + $rr close + } test {replica allow read command by default} { r get foo diff --git a/tests/unit/cluster/transactions-on-replica.tcl b/tests/unit/cluster/transactions-on-replica.tcl index b53af58cac..5bca9e6a37 100644 --- a/tests/unit/cluster/transactions-on-replica.tcl +++ b/tests/unit/cluster/transactions-on-replica.tcl @@ -53,6 +53,30 @@ test "MULTI-EXEC with write operations is MOVED" { assert {[string range $err 0 8] eq {EXECABORT}} } +test "write command is QUEUED, then EXEC should be MOVED after failover" { + set rr [valkey_client] + $rr MULTI + assert {[$rr SET foo bar] eq {QUEUED}} + + $replica CLUSTER FAILOVER FORCE + wait_for_condition 50 1000 { + [status $primary master_link_status] == "up" + } else { + fail "FAILOVER failed." + } + + catch {$rr EXEC} err + assert {[string range $err 0 4] eq {MOVED}} + $rr close + + $primary CLUSTER FAILOVER FORCE + wait_for_condition 50 1000 { + [status $replica master_link_status] == "up" + } else { + fail "FAILOVER failed." + } +} + test "read-only blocking operations from replica" { set rd [valkey_deferring_client -1] $rd readonly